Writing Peer-to-Peer Applications Using .NET, Part 1 (PNRP)

 

The March CTP of the .Net Framework (codenamed “Orcas”) was released earlier this month. In the CTP you will find a new namespace (System.Net.PeerToPeer) which exposes a rich suite of APIs to make writing Peer-To-Peer (P2P) apps easier. More specifically, the namespace includes APIs for the Peer Name Resolution Protocol (PNRP), People Near Me, Serverless Presence and Application Invitation technologies. This rest of this post will focus on PNRP – part 2 of this series will start to dig into the other technologies being added to the System.Net.PeerToPeer namespace.

What is PNRP?

In short, PRNP is a serverless name resolution technology. It allows one to create an identifier (known as a Peer Name), associate that identifier with data (ip addresses, port #, binary blob, etc) and publish it for other peers to be able to resolve. Sounds a bit like publishing and resolving a DNS host name (ie. Microsoft.com) doesn’t it? Conceptually both technologies allow publishing and resolving identifiers, however, there are key differences that make PNRP well suited for P2P applications. Quoting MSDN:

“Another point of contrast between client/server and peer-to-peer networking is the use of the Domain Name System (DNS). Server computers are typically registered in DNS so that client computers can resolve a name to the IP address of the server computer. Client computers are typically not registered in DNS for the following reasons:

- Many client computers have transient connectivity; they connect for unpredictable amounts of time and can be assigned a new IP address for each connection.

- Client computers do not have shared resources and do not respond to requests for resources. Therefore, other computers do not need to resolve the names of client computers. DNS address records for client computers are not necessary.

Peer computers, on the other hand, have resources to share. However, they still have transient connectivity. Peer computers could use DNS dynamic update to register their names, however, very few DNS servers on the Internet support DNS dynamic update. To be successful for peer-to-peer networking, peer computers must not rely on the existing DNS infrastructure. Therefore, there must be a mechanism to resolve peer names to their addresses that does not rely on DNS. For Windows Peer-to-Peer Networking, this mechanism is Peer Name Resolution Protocol (PNRP) and is described in Peer Name Resolution Protocol .”

Code – Create and Publish a Peer Name

Ok, hopefully now it is clear what PNRP is and why it is so valuable for P2P scenarios. The code below shows how to use the new namespace, System.Net.PeerToPeer to create a PeerName and publish it for other peers to resolve.

NOTE: Be sure to add a reference to System.Net.dll in your VS project as the System.Net.PeerToPeer.dll resides in this new assembly.

 

using System;

using System.Collections.Generic;

using System.Text;

using System.Net.PeerToPeer;

using System.Net;

namespace PnrpSamples

{

    // PNRP Registration Sample

    class Program

    {

        static void Main(string[] args)

        {

            // Creates a secure (not spoofable) PeerName

            PeerName peerName = new PeerName("MikesWebServer", PeerNameType.Secured);

            PeerNameRegistration pnReg = new PeerNameRegistration();

            pnReg.PeerName = peerName;

            pnReg.Port = 80;

            //OPTIONAL

            //The properties set below are optional. You can register a PeerName without setting these properties

            pnReg.Comment = "up to 39 unicode char comment";

            pnReg.Data = System.Text.Encoding.UTF8.GetBytes("A data blob associated with the name");

            /*

             * OPTIONAL

             *The properties below are also optional, but will not be set (ie. are commented out) for this example

             *pnReg.IPEndPointCollection = // a list of all {IPv4/v6 address, port} pairs to associate with the peername

             *pnReg.Cloud = //the scope in which the name should be registered (local subnet, internet, etc)

            */

            //Starting the registration means the name is published for others to resolve

            pnReg.Start();

            Console.WriteLine("Registration of Peer Name: {0} complete.", peerName.ToString());

            Console.WriteLine();

            Console.WriteLine("Press any key to stop the registration and close the program");

            Console.ReadKey();

            pnReg.Stop();

   }

    }

}

Output:

Registration of Peer Name: af32f166bc99b4aeabb3e21b152a0eed07daa829.MikesWebServer complete.

Press any key to stop the registration and close the program

At this point we have published a PeerName which other PNRP enabled applications can resolveJ. Later in this post, I show how to write an application that resolves the PeerName we just published, but first, I’m sure you are wondering where on earth the “af32f166bc99b4aeabb3e21b152a0eed07daa829” part of the PeerName came from. To understand this, one needs to know a bit about how Peer Names are constructed. Every PeerName is made up of two parts, an authority, followed by a period and then a classifier. The “af32f166bc99b4aeabb3e21b152a0eed07daa829” in the PeerName created by the application above is the authority. Authorities come in two flavors:

  • 40 hex characters for secure (ie. not spoofable) Peer Names
  • A single character (the number 0) for unsecure Peer Names

Authorities are generated by the P2P infrastructure, will be different for each user, and are composed of a SHA1 hash of the public key associated with the PeerName. The classifier portion of the PeerName is simply a user defined string of Unicode characters. For all the details of how a PeerName is constructed, click here.

Code – Resolve a Peer Name

The following code snippet shows how to synchronously resolve a PeerName (async methods are also available). It is important to note that once a PeerName is published (as above), it remains published until:

  • The publisher explicitly stops publishing the name (as in the code example above) OR
  • The PeerNameRegistration object representing the publication goes out of scope OR
  • The process which published the PeerName ends

This means that you need to leave the above publisher application running while you execute the code below:

using System;

using System.Collections.Generic;

using System.Text;

using System.Net;

using System.Net.PeerToPeer;

namespace PnrpResolver

{

    class Program

    {

        static void Main(string[] args)

        {

            // create a resolver object to resolve a peername

            PeerNameResolver resolver = new PeerNameResolver();

            // the peername to resolve must be passed as the first command line argument to the application

            PeerName peerName = new PeerName(args[0]);

            // resolve the PeerName - this is a network operation and will block until the resolve completes

            PeerNameRecordCollection results = resolver.Resolve(peerName);

            // Display the data returned by the resolve operation

            Console.WriteLine("Results for PeerName: {0}", peerName);

            Console.WriteLine();

            int count = 1;

            foreach (PeerNameRecord record in results)

            {

                Console.WriteLine("Record #{0} results...", count);

               

                Console.Write("Comment:");

                if (record.Comment != null)

                {

                    Console.Write(record.Comment);

                }

                Console.WriteLine();

                Console.Write("Data:");

                if (record.Data != null)

                {

                    Console.Write(System.Text.Encoding.ASCII.GetString(record.Data));

                }

                Console.WriteLine();

                Console.WriteLine("Endpoints:");

                foreach (IPEndPoint endpoint in record.EndPointCollection){

                    Console.WriteLine("\t Endpoint:{0}", endpoint);

                    Console.WriteLine();

                }

                count++;

            }

            Console.ReadKey();

        }

       

    }

}

Output:

Results for PeerName: af32f166bc99b4aeabb3e21b152a0eed07daa829.MikesWebServer

Record #1 results...

Comment: up to 39 unicode char comment

Data: A data blob associated with the name

Endpoints:

Endpoint:fe80::8d02:5afb:549d:4a78%10:80

Endpoint:10.252.40.98:80

Platform Support & Questions/Comments

All the APIs shown above are available in the March “Orcas” .Net Framework CTP. Note: The CTP does not yet support Windows Vista.

The PNRP APIs are supported on Windows Vista (all SKUs except starter edition), Windows Server Longhorn as well as Windows XP (with the PNRP update for XP installed).

If you have any questions about the APIs, I encourage you to post them to the System.Net forum. For suggestions with respect to this or any of the System.Net APIs, please email nclasks at microsoft.com

Cheers,

Mike Flasko