Peer To Peer

Harness The Power Of P2P Communication In Windows Vista And WCF

Justin Smith

This is article based on a prerelease version of Windows Vista and the .NET Framework 3.0. All information is subject to change.

This article discusses:

  • Peer-to-peer networking basics
  • P2P support in Windows Vista and Windows Communication Foundation
  • Developing with PeerChannel
This article uses the following technologies:
Windows Vista, .NET Framework 3.0

Code download available at:P2P2006_10.exe(668 KB)

Contents

P2P Basics: Mesh Networks
Peer Name Resolution Protocol
PeerChannel
People Near Me
Conclusion

When most of us think about peer-to-peer (P2P) applications, we instinctively think of instant messaging applications, simple file sharing programs, and games. For the most part, we have been conditioned to default to the client/server model when considering distributed application designs and hardly give P2P models even passing thought, especially for business applications. The primary reason for this focus on the client/server model is simple: P2P application development used to be expensive and time-consuming.

Traditionally, challenges to P2P application development have included the need to develop proprietary protocols for message exchange, having to locate and connect with instances of an application that are hidden behind a Network Address Translation (NAT) or a firewall, and the need to support the inevitable infrastructure required to locate applications in a wide-area network (WAN). These challenges, while surmountable, have represented a substantial barrier, and as a result, many of us never consider the amazing collaborative functionality P2P applications provide.

These barriers will be dramatically reduced with Windows Vista™ and the accompanying .NET Framework 3.0 release. The combination of Windows Vista enhancements to Peer Name Resolution Protocol (PNRP), People Near Me (PNM), and the introduction of PeerChannel in Windows® Communication Foundation have made P2P applications much more approachable. I personally expect increased activity in the P2P arena following the release of Windows Vista.

P2P development in Windows Vista is a huge topic, and no single article can cover it fully. So instead of attempting the impossible, I'll introduce some of the different P2P technologies in Windows Vista, and provide background for your P2P development efforts.

In addition to assuming you have a basic understanding of Windows Forms, I also assume you are somewhat familiar with writing Windows Communication Foundation applications. If not, you may want to get started by reading some of the content either in the Windows SDK or at https://archive.msdn.microsoft.com/netfxsamples.

P2P Basics: Mesh Networks

Before diving into specific P2P technologies, it is important to examine some basic principles of P2P applications. For starters, a P2P application is one that connects directly with other instances of the application. In P2P language, each instance of the application is called a node. A named and connected grouping of these nodes is often referred to as a mesh. As a result, technologies that facilitate P2P application development are frequently referred to as mesh technologies. PNRP, PeerChannel (in Windows Communication Foundation), and PNM are all examples of mesh technologies in Windows Vista.

Mesh Topologies All Windows Vista mesh technologies produce meshes that have roughly the same topology. A mesh topology is generally an abstraction of the connection pattern amongst the nodes in the mesh. To illustrate, imagine, in your mind's eye, a mesh. I'll bet you imagined a mesh somewhat similar to the one in Figure 1.

Figure 1 Fully Connected Mesh

Figure 1** Fully Connected Mesh **

Every one of the four nodes in the mesh in Figure 1 is connected to all of the other nodes in the mesh. In other words, if there are N nodes in the mesh, each node maintains N-1 connections. A mesh that meets this criterion is considered to be fully connected. Fully connected meshes are seldom a good idea; to see why, let's consider the connection between nodes.

Nodes in a mesh typically communicate using existing and familiar transports. Like all modern operating systems, Windows Vista leverages TCP/IP and UDP for network communication. If TCP/IP is the chosen transport of a fully connected mesh, then each node in a fully connected mesh of N nodes must create or accept N-1 sockets. As N increases, this model clearly becomes infeasible. For example, if you consider the case of N=1000, then each node would need to maintain 999 sockets, and this simply won't work.

To solve the problems of scalability and WAN connectivity, you must look to a mesh that is partially connected, like the one in Figure 2. As the name implies, nodes in a partially connected mesh are connected only to a few of the other nodes in the mesh. In P2P terms, these adjacent nodes are called neighbors. In general, a partially connected mesh places fewer resource demands on each node, thereby dramatically increasing the scalability of a mesh. In theory, a partially connected mesh can grow to include all of the applications on all of the computers in the world.

Figure 2 Partially Connected Mesh

Figure 2** Partially Connected Mesh **

Joining a Mesh The way a node joins a mesh depends on the mesh technology used, but generally speaking, a prospective node must use the mesh name to resolve the physical addresses of one or more nodes already in the mesh. If you assume a partially connected mesh, the result of the mesh name resolution is a subset of the physical addresses available in the mesh. Upon receipt of the physical addresses of one or more physical nodes in the mesh, the prospective node must then connect to one, some, or all of those addresses. After connecting to the mesh, the newly added node must then ready itself to respond to subsequent mesh name resolutions from other prospective nodes.

Mesh name resolution is a complex topic. Much of this complexity is due to the fact that, in many cases, the resolution of a mesh name depends on one or more additional meshes. To illustrate, consider the mesh used by the U.S. Postal Service. More specifically, let's assume that I need to send a package to my friend Rusty. To send the package, I may need to go to a post office. If I do not know the location of the post office nearest to me, I may go to the Internet and look up the address of the nearest one. In an abstract sense, "connecting" to the U.S. Postal Service mesh required me to first go to the biggest mesh of all, the Internet, to resolve the address of the nearest node. In other words, you may use a mesh to resolve addresses contained in another mesh. I will discuss this concept more in the PNRP section of this article.

Communicating with Other Nodes Once a node is connected to a mesh, it may communicate with other nodes through one of two means: mesh flooding (also called multiparty messaging), or directional messaging. As the name implies, mesh flooding is an attempt to send a message to all nodes in the mesh. In general, a node in a mesh can propagate a message to all other nodes by sending the message to all of its neighbors. Upon receiving this message, the neighbor of the sending node is responsible for forwarding the message to its neighbors, and so on. In contrast, directional messaging is an attempt to direct a message to a particular node in the mesh. In a partially connected mesh, the initial sending node may not be connected to the intended recipient. If this is the case, then the initial sending node must send the message to one or more of its neighbors. A neighbor may be connected to the intended recipient. If so, then the neighbor can forward the message to it. If not, then the neighbor makes a guess about which of its neighbors may itself be connected to the intended recipient.

Meshes are seldom static. In most P2P applications, nodes may frequently join and leave the mesh, either due to changes in network connectivity, or, in the case of an instant messaging application, due to a user starting and stopping the application. In addition to the natural changes in a mesh, most mesh technologies have some mechanism to maintain themselves. In general, the goal of mesh maintenance is to repair or tune the mesh so that it operates more efficiently or is more robust. It is important to note that each mesh technology implements mesh maintenance differently.

Peer Name Resolution Protocol

As implied by its name, PNRP is designed to resolve physical addresses based on, among other things, a mesh name. PNRP is available for Windows XP Service Pack 1 (SP1) with the Advanced Networking Pack, Windows XP SP2, and Windows XP Professional x64 Edition. Windows Vista will also ship with PNRP version 2. At the simplest level, PNRP is itself a P2P application that takes the form of a Windows service, and the mesh of PNRP nodes is used exclusively for discovering the physical addresses of nodes participating in other meshes. (See the sidebar "Installing PNRP on Windows XP" for more on this.)

PNRP and IPv6 PNRP is built on Internet Protocol version 6 (IPv6). Since IPv6 is fairly new to most developers, it is important that I mention at least one significant aspect of IPv6 before I discuss the mechanics of PNRP. In IPv6, an address is a 128-bit value (which allows for approximately 3.4×1038 address combinations). This size of the IPv6 address pool enables one of the most important features of IPv6, end-to-end addressing, even when these addresses are carved into multiple subnets, and tucked away behind a NAT. For more information about IPv6, and the technologies that allow its use in an IPv4 infrastructure, see microsoft.com/technet/itsolutions/network/ipv6/introipv6.mspx.

A PNRP Example The PNRP function prototypes, structures, and error codes are defined in the p2p.h header file of the Windows SDK. If an application wishes to register a mesh name with PNRP, it must do so through the Windows API via unmanaged code, or in managed code through the P/Invoke facilities of the common language runtime (CLR). Currently, there is no managed wrapper included in the .NET Framework for the PNRP part of the Windows API. You can, however, access PRNP by using the netsh command-line utility. Through netsh, you can register a new PNRP name with PNRP, as shown here:

c:\temp>netsh netsh>p2p pnrp peer netsh p2p pnrp peer>add 0.justinsmith Ok.

The command-line parameter 0.justinsmith is the P2P name. When this command executes, the PNRP infrastructure generates a PNRP ID, associates that PNRP ID with the P2P name, and assigns that PNRP ID an IPv6 and IPv4 address. If you go to another machine that has PNRP installed and started on it, you can resolve the mesh name 0.justinsmith with the netsh command here:

netsh p2p pnrp peer>resolve 0.justinsmith Resolve started... Found: Comment: gonzo Addresses: [0000:0000:0000:0000:0000:0000:0000:0001]:8350 udp 192.168.42.100:8350 tcp

The output of the resolve command requires some explanation. First, the Comment field represents the machine name that 0.justinsmith was registered on (I name my machines after the Muppets). This field is automatically populated from netsh, and cannot be used as part of the resolution process. Secondly, notice the IPv6 and IPv4 addresses assigned to the node. This is a feature of both netsh and the Teredo transition technology that allows IPv6 traffic over an IPv4 network. Admittedly, I have just begun to scratch the surface of PNRP, but I have shown that PNRP allows me to use a P2P name to resolve an IP address. For more information about PNRP, see microsoft.com/technet/prodtechnol/winxppro/deploy/p2pintro.mspx.

PeerChannel

One of the major benefits of Windows Communication Foundation is that it offers a universal programming model for many different flavors of distributed applications. For example, the code required to write a distributed application that communicates via binary encoded messages over TCP/IP is incredibly similar to the code required to write a distributed application that communicates via WS-* compliant, interoperable messages over HTTP. One of the lesser-known features of Windows Communication Foundation is its support for building P2P applications using this same universal programming model. Because of its support for P2P applications, one may look at Windows Communication Foundation as a mesh technology, but in reality, only the PeerChannel Windows Communication Foundation module is dedicated to building P2P applications. For this reason, the term PeerChannel is commonly used to refer to the P2P capabilities of Windows Communication Foundation. Regardless of the way you refer to it, the PeerChannel in Windows Communication Foundation hides virtually all of the complexity traditionally associated with developing a P2P application and is, in my view, a game changer in the P2P application development arena.

The PeerChannel Mesh The PeerChannel mesh is designed for message flooding. However, PeerChannel contains mechanisms that can propagate a message to part of the mesh, rather than to the entire mesh. For this reason, it is more accurate to say that a PeerChannel mesh is designed for multiparty messaging.Installing PNRP in Windows XP

By default, PNRP is not installed on Windows XP. To install it, start the Add/Remove Programs applet in Control Panel, select Add/Remove Windows Components, select Networking Services. Next, click the Details button, then check the Peer Networking checkbox, and select OK/Next. These steps install several P2P Windows Services (PNRP is among them), but do not configure them to start automatically. To start PNRP, go to the Service Control Manager, and start the Peer Networking service. This will start, among other things, the PNRP service.

A P2P application can register many nodes with the PNRP service, and each node in the PNRP mesh is composed of a P2P Name and a PRNP ID. Generally speaking, a P2P Name represents a mesh name (like a mesh name in a PeerChannel application), and is dictated by the P2P application, while the PNRP ID is assigned to a registered node by the PNRP infrastructure. The PNRP mesh is designed for directional messaging, and uses PNRP IDs to structure the mesh.

The structure of the PeerChannel mesh is dictated by the number of neighbors each node is connected to. To this end, a PeerChannel mesh actively maintains the structure of the mesh. The effect of this maintenance is a robust, evenly distributed mesh. To be more specific, a node in the mesh strives to maintain between two and seven connections to neighbors. These thresholds represent a balancing act between resource demands on the local node and maintaining a robust mesh.

If a node enters the mesh with three neighbors, and two of its neighbors leave the mesh, then that node will start a maintenance cycle in an attempt to acquire new connections to neighbors. Likewise, a node with less than seven neighbors will accept new connections until it has seven connections to neighbors. A PeerChannel node is considered ideally connected when it has three neighbors, but a node will accept up to seven neighbors so that a node that has fallen below the minimum threshold of neighbors can quickly obtain new neighbors. It is important to note that your application code cannot change these thresholds or exert any control over the maintenance of the mesh. These details are taken care of entirely by the PeerChannel infrastructure on a node-by-node basis.

PeerChannel offers both PNRP and custom resolvers as means for a prospective node to discover the addresses of nodes already in the mesh. Regardless of the chosen method of resolution, the general idea is the same: pass the name of the mesh to the resolver and receive a list of IP addresses of other nodes in the mesh. Once the resolution produces a list of addresses, the prospective PeerChannel node concurrently connects to each of the addresses. When a node already in a PeerChannel mesh receives one of the connection requests, it either accepts or refuses the connection. If the connection is accepted, the existing node sends the newly joined node a welcome message that contains, among other things, a list of the addresses of other nodes in the mesh. If the connection is refused, then the existing node sends the prospective node a refusal message that contains a reason for refusal and a list of the addresses of other nodes in the mesh.

The important point here is that mesh name resolution (via PNRP or a custom resolver) is not the only way a list of addresses is returned to a prospective node in PeerChannel. This feature allows nodes to become ideally connected more quickly than if mesh name resolution was the only means by which a prospective node could obtain an address. Also, this feature allows nodes in the mesh to exert control over how many neighbors a node has, which in turn, impacts the robustness of the mesh.

Communication within a PeerChannel mesh is tuned to keep repetitive message passing to a minimum. When a node in the mesh sends a message to the mesh, it is really sending a message to its neighbors. Upon receipt of a message, each neighbor inspects the message and then forwards the message to its neighbors. If a PeerChannel node receives a message from a neighbor, it will not forward that message back to that neighbor. Also, if a PeerChannel node frequently receives a message from a neighbor that it has previously received and processed, the connection to that neighbor may be terminated in the next maintenance cycle. These features are implemented by a local cache on each node. Internally, each node in a PeerChannel mesh caches the value of the WS-Addressing Message ID and an identifier of the neighbor that delivered the message. A node checks this cache when deciding which neighbors to deliver the message to. The combination of these features results in a mesh that is tuned to deliver messages to nodes in the mesh with a minimum of repetition and network bandwidth consumption.

As I mentioned previously, a PeerChannel node can also send a message to a subset of the nodes in the mesh. This is accomplished by assigning a hop count to a message, which is actually a way to track the number of nodes the message has been forwarded through. Do not confuse this mechanism with directional messaging, in which a message is targeted to a particular node. Rather, a hop count is a way to draw a fuzzy boundary around the nodes that will receive the message. For example, if a PeerChannel node (Node A) has three neighbors and sends a message to the mesh with a hop count of 1, then that message will be delivered to three nodes. Likewise, if each of Node A's neighbors has three unique neighbors, and Node A sends a message to the mesh with a hop count of 2, then the message will be delivered to nine nodes. However, if any of Node A's neighbors have common neighbors, then this number will decrease proportionately.

Physically, a hop count is expressed in a message as an integer in a header block. When a node receives a message that has a hop count, it inspects the value of the hop count. If the value is greater than zero, the node decrements the hop count monotonically, and forwards the message (with the decremented hop count value) on to the appropriate neighbors. If a received message contains a hop count of zero, then the message is not forwarded. It is also important to note that the hop count header block is excluded from message signing, so changing this value does not impact the integrity of the digital signature applied to the message, and prevents the overhead associated with repeatedly generating digital signatures and serializing them into the appropriate parts of the message.

PeerChannel Example Let's build a simple P2P application, called PictureViewer, using PeerChannel and Windows Forms. The purpose of the application, as you can tell from its name, is to allow all nodes in the mesh to view the same picture. At a high level, the steps required to build this application are as follows:

  1. Define the basic Windows Forms boilerplate code.
  2. Add controls to the form.
  3. Define the necessary Windows Communication Foundation service contract.
  4. Write the Windows Communication Foundation code required to connect to and receive messages from the mesh.
  5. Write the code required to send a message to other nodes in the mesh.

Figure 3 shows the finished app. Steps 1 and 2 are necessary when developing any Windows Forms application, so I won't show them here. As with any Windows Communication Foundation application, the first development step is to define the service contract. A service contract that will be used by PeerChannel is similar to other Windows Communication Foundation contracts except that PeerChannel requires that all OperationContractAttribute annotations set the IsOneWay instance property to true. This property states that the receiver of the message should not send a reply. If you want the receiver to send a reply, you may define the service contract as a duplex contract, but each OperationContractAttribute annotation must still set the IsOneWay instance property to true. For the purposes of this example, I won't create a duplex contract (there are several examples of duplex contracts in the Windows SDK). The contract I will use is shown here:

[ServiceContract] interface IPictureViewer { [OperationContract(IsOneWay = true)] void SharePicture(Stream stream); }

Figure 3 The PictureViewer P2P Application

Figure 3** The PictureViewer P2P Application **(Click the image for a larger view)

Notice that the SharePicture interface method is annotated with the OperationContractAttribute attribute, and the IsOneWay instance property is set to true. The SharePicture operation accepts a System.IO.Stream as a parameter because this operation will be used to propagate the bytes of a picture to other nodes in the mesh.

With our service contract defined, it is now time to add the Windows Communication Foundation code that will connect our application to the PeerChannel mesh and passively wait for messages from the mesh. First, I implement my newly defined service contract in the Form. Then, I define a field of type ServiceHost. Received messages will be dispatched to a single instance of the frmPictureViewer type. To indicate this functionality, I must assign the proper ServiceBehavior to the frmPictureViewer type. These two steps are shown in Figure 4.

Figure 4 Implementing the Service Contract

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public partial class frmPictureViewer : Form, IPictureViewer { // host the receiver ServiceHost host; // method to be invoked upon receipt of a message public void SharePicture(Stream stream) { // get the image Image image = Bitmap.FromStream(stream); // show the image in the picture box on the form pbView.SizeMode = PictureBoxSizeMode.StretchImage; pbView.Image = image; } ... // other members elided for clarity }

Next, I must instantiate a ServiceHost, add an endpoint, and begin listening for incoming messages. Since I am building a Windows Forms application, the logical place to do this is the constructor of the form, as shown in Figure 5.

Figure 5 Attempt to Join Mesh and Listen for Messages

public frmPictureViewer() { InitializeComponent(); StartReceiving(); } private void StartReceiving() { // define the meshname and set up the peer binding // with the PNRP resolver Uri meshAddress = new Uri("net.p2p://pictureView"); NetPeerTcpBinding binding = new NetPeerTcpBinding(); binding.Resolver.Mode = PeerResolverMode.Pnrp; binding.Security.Transport.CredentialType = PeerTransportCredentialType.Password; binding.MaxReceivedMessageSize = 700000L; host = new ServiceHost(this); host.AddServiceEndpoint(typeof(IPictureViewer), binding, meshAddress); // define the password and get a cert for digsig host.Credentials.Peer.MeshPassword = "JustinSmith"; host.Credentials.Peer.Certificate = GetCertificate(); // attempt to join and listen for messages host.Open(); }

At this point, I have done all I need to in order to connect to the mesh and listen for messages. When compared to standard Windows Communication Foundation code, the only things that are different are the scheme of the Uri (net.p2p), the binding (NetPeerTcpBinding) that I am using, and the addition of password-based security. It is important to note that I have opted to put the mesh password directly in the code. Don't do this in your live applications if you want the mesh password to be a secret.

As soon as I call ServiceHost.Open, our application will attempt to resolve the mesh name (pictureView) via PNRP. At this point, I can verify that our PeerChannel application is using PNRP by running a netsh command to list the registered peer names. If PNRP can resolve the mesh name to one or more IP addresses, then our application will attempt to connect to those nodes. If not, then that node will be the first node in the mesh. As stated previously, existing nodes will either accept or reject the connection by sending either a welcome message or a refused message. The important point here is that this may be happening after the call to ServiceHost.Open returns.

Sending a Message to Other Nodes Before I share a picture, I must first load the picture. The code required to do this is basic Windows Forms code: first, instantiate an OpenFileDialog, get a Stream, convert that Stream into an Image, then reference the Image through the PictureBox.Image property. Wait a minute, isn't that what the SharePicture method does? As a matter of fact, it is. In essence, all I need to do to load the image into the PictureBox is call the SharePicture method, passing the Stream returned from OpenFileDialog.OpenFile as a parameter.

To send a message that contains the picture to the other nodes in the mesh, I must write a few lines of code, but this code is nearly identical to code you would write in any other Windows Communication Foundation application. For starters, I need to define fields in my form of type ChannelFactory<IPictureViewer> and IPictureViewer. Next, I need to instantiate these variables in the constructor of the form. These steps are shown in Figure 6.

Figure 6 Creating the Sending Infrastructure

ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public partial class frmPictureViewer : Form, IPictureViewer { ChannelFactory<IPictureViewerClient> channelFactory; IPictureViewer channel; public frmPictureViewer() { InitializeComponent(); StartReceiving(); } private void StartReceiving() { // other code elided for clarity channelFactory = new ChannelFactory<IPictureViewerClient>( binding, new EndpointAddress(meshAddress)); channelFactory.Credentials.Peer.MeshPassword = "JustinSmith"; channelFactory.Credentials.Peer.Certificate = GetCertificate(); channel = channelFactory.CreateChannel(); } ... // other code elided for clarity }

Notice that I must use the same mesh password and certificate (used to create a digital signature of the message) I used when setting up the ServiceHost. Other than that, this code is identical to code required in non-PeerChannel Windows Communication Foundation applications.

Now that I have built my sending infrastructure, I can use it to send a message to the other nodes in the mesh. To do this, I simply write an event handler for the share button, as shown here:

private void btnShare_Click(object sender, EventArgs e) { using(MemoryStream stream = new MemoryStream()) { Image image = pbView.Image; image.Save(stream, ImageFormat.Jpeg); // store image in stream stream.Position = 0; // reset the position channel.SharePicture(stream); // send a message to the mesh } }

In a nutshell, PeerChannel greatly simplifies P2P application development. The fully functioning version of PictureViewer is about 150 lines of source code, and most of that is dedicated to Windows Forms infrastructure. The fully functional application includes a hop count implementation, and is available for download at the MSDN®MagazineWeb site.

People Near Me

PNM is a mesh technology integrated into Windows Vista that allows groups of nearby devices and people to discover, connect, invite, and collaborate with each other. PNM is well suited for tasks such as playing a game in a coffee shop with several other nearby people, sharing your desktop with a co-worker, or even connecting to a projector in a conference room. The capabilities offered by PNM are vast, and it is reasonable to assume that once released, the developer community will find new and inventive ways to leverage this technology. It is important to note that PNM is a completely opt-in mesh technology and is turned off by default.

PNM architecture is composed of, among other things, a P2P application called p2phost.exe. When running, this process creates a mesh by connecting to instances of p2phost.exe on other machines. In general, the purpose of this mesh is directional messaging. More specifically, PNM is designed to resolve local nodes, and communicate with a subset of those local nodes. The PNM API is available as part of the Windows API, and for the most part, focuses on configuring the behavior of p2phost.exe.An Example of Real-World People Near Me

PNM, while it contains an executable, requires another application to leverage its capability. The following scenario illustrates how PictureViewer can use PNM to provide collaborative features:

  1. Tom installs PictureViewer on his new notebook computer running Windows Vista. The installer registers PictureViewer with PNM.
  2. Tom takes his notebook computer to a coffee shop and signs in to PNM. When he is signed in, p2phost.exe begins discovering other nodes in the PNM mesh.
  3. Harry, who also installed PictureViewer, is also at the coffee shop with his notebook computer. When Harry signs in to PNM, his instance of p2phost.exe begins discovering other nodes in the PNM mesh.
  4. Harry and Tom were high school classmates and have not seen each other in many years. They recognize each other from across the room, and begin a conversation. Harry offers to show Tom pictures of his family.
  5. When searching for the pictures, Harry realizes that he hasn’t downloaded the latest pictures of his family from his camera, and he offers to show Tom the pictures later.
  6. Tom decides to show Harry some photos of his family, and starts PictureViewer. Since PictureViewer is integrated with PNM, he invites Harry, through PictureViewer, to look at pictures of his family.
  7. After Tom sends the invitation to Harry, Harry receives a notification on his taskbar that Tom has invited him to start PictureViewer.
  8. Harry accepts the invitation, and PNM starts PictureViewer. After PictureViewer starts, pictures of Tom’s family appear on Harry’s instance of PictureViewer.
  9. Harry promises to show Tom the pictures of his family in the future through PictureViewer. To this end, Harry adds Tom to his contact list by selecting menu items in PictureViewer. Tom does the same.
  10. Some time in the future, Harry and Tom are both away on business trips in different cities. Harry signs in to PNM and opens PictureViewer. He immediately notices that Tom has signed in to PNM also.
  11. Since Harry has downloaded the latest pictures of his family, he invites Tom, through PictureViewer, to take a look at the pictures.
  12. 12.Tom receives and accepts Harry’s invitation. Upon the acceptance of the invitation, PNM launches the PictureViewer app. After PictureViewer starts, Tom sees the long-awaited pictures of Harry’s family.
  13. While PictureViewer may not be the most efficient means to share photos, this story sufficiently tells the PNM story. In each of these steps, PictureViewer is leveraging a different part of the PNM API.

Broadly speaking, the main categories of the PNM API include functions, structures, events, and error codes that provide the ability to register an application with PNM, invite others to join a collaboration session, start a registered application, create a persistent contact, and invite a contact that is no longer local. The sidebar "An Example of Real-World People Near Me" illustrates the process. Notice that there is no support for an application to communicate using PNM. In PictureViewer terms, this means that the message passing between Tom and Harry's instances of PictureViewer explained in the sidebar is still handled by PeerChannel.

Conclusion

P2P application development is a very broad topic, and for most developers, a fairly new one. With the release of Windows Vista and the .NET Framework 3.0, the traditional barriers to entry in P2P application development will be dramatically lowered. My guess is that the advances in technology, like PNRP, IPv6, and the advent of new, more productive platforms, like PeerChannel and PNM, will usher in a new era of P2P application development. The end result will be more collaborative applications that offer functionality we can only begin to imagine.

Justin SmithJustin Smith is a trainer and consultant at Wintellect. He is currently writing Applied Windows Communication Foundation Programming for Microsoft Press, scheduled for publication in January 2007, and is the author of Wintellect's Mastering Distributed Applications course. Justin can be reached at justins@wintellect.com.