The World’s Leading Microsoft .NET Magazine
   
 
The .NET Addict's Blog

My Top Tags

                                                           

My RSS Feeds








Latest Diggs - Programming

Internet Blogs - Blog Top Sites

Site Hits

Total: 2,502,482
since: 19 Jan 2005

Orcas' Hidden Gem - The managed PNRP stack

posted Fri 11 May 07

Lately there's been a lot of buzz about Orcas. You keep hearing about Silverlight and the Entity Framework and Jasper and Astoria and who knows how many other code names. One of the things that you don't hear about is PNRP. Why? I haven't the faintest idea because this is some of the coolest stuff to surface as a .NET API since .NET 1.0 reshaped our opinion of streams.

While experimenting with Orcas, I noticed that the PNRP (Peer Name Resolution Protocol) did in fact have a managed API. It is exposed through System.Net.PeerToPeer in the Beta 1 bits. PNRP is basically a service registry. Whenever you have a service that has become available that you want other clients on your network to know about, you register that information with PNRP. The great thing about PNRP is that you don't need a server like you do with DNS. You register the peer name with your local PNRP (Windows Service on XP SP 2 w/PNRP update or Vista RTM) service. If you are near other PNRP implementations, they will share information and propogate the service registration depending on the scope you've chosen for your service name.

Why is this cool and why should you care? Simple. Peer networking is not all about sharing music and downloading l33t w4rez. Let's say you have a corporate backbone that's running all of your company's systems. Now let's say that you bring up a client application (which could be a desktop app or even a public-facing web application). How does your client application know where to go in order to find the service for submitting purchase orders? Sure, you could hard-code it, or even put it in an App.config, but a lot of the time people actually end up writing complex infrastructures to deal with service registries. Also, let's face it, UDDI sucks.

What if your client application were to be able to come up and do a quick PNRP query and get results that indicate there are 3 servers on the network currently implementing the purchase order service. Additionally, each service registry entry has a little bit of info to help your client application pick which service to use. This is where it gets good: WCF + PNRP = Pure Gold.

So I set off to write a sample application. Basically I created a couple of host servers that pretend to be photo libraries. As each service comes up, it not only turns on the WCF listeners, but it registers the service location with PNRP. Then, a single client comes up and queries the list of available network photo albums. For each one that it finds, it dynamically connects to that photo album and retrieves an icon representing the album by invoking a method on the advertised WCF photo album service.

The end result is an application that looks like this:

It might not look like much, but this application is enumerating a list of WCF services that were dynamically registered by WCF host applications. In addition, the client application is connecting to each of these advertised services and querying the service for additional information (in this case, an icon). 

To take a look at how ridiculously easy this is, here's the code that starts the WCF photo album service and registers a publicly available peer name with PNRP:

ServiceHost host = new ServiceHost(typeof(PhotoService));
host.Open();
PeerName pName = new PeerName(
                 "PhotoService",
                 PeerNameType.Unsecured);
PeerNameRegistration reg = new PeerNameRegistration(
                           pName, Int32.Parse(advertPort));
reg.Comment = advertName;
reg.Data = System.Text.ASCIIEncoding.ASCII.GetBytes(
    advertData);
reg.Start();
 

The advertPort is a port number defined in the app.config file, and advertData is a string containing a comment description (such as "Bob's Photos") that was also defined in the app.config of the service host. There is a limited amount of data you can store on the peer name registration, so keep it short and sweet. If you need additional information about the service, you can connect to the service and invoke methods on it (like I"m doing to obtain the icon for the service).

Here's the code on the client that enumerates the list of all "PhotoService" services on the network registered with PNRP. For each enumerated service, the client ignores the IPv6 address, and connects to the IPv4 address, establishes the WCF proxy instance, obtains the image icon (in a Hex64 encoded string of bytes), and saves it (the idea was I might cache the file so I don't have to query every time), and then finally binds the GUI to the URI of the locally cached image:

public void EnumeratePhotoServices()
{
ModelRoot model = ModelRoot.Current;
model.DiscoveredServices.Clear();
PeerNameResolver resolver = new PeerNameResolver();
PeerNameRecordCollection peers =
    resolver.Resolve(new PeerName("0.PhotoService"));
foreach (PeerNameRecord peer in peers)
{
    Console.WriteLine("{0}", peer.PeerName.ToString());
    DiscoveredService service = new DiscoveredService();
    service.Name = peer.PeerName.ToString();
    service.Comment = peer.Comment;
    service.Data = System.Text.ASCIIEncoding.ASCII.GetString(
        peer.Data);
    service.EndPoints = peer.EndPointCollection;
    foreach (IPEndPoint ep in peer.EndPointCollection)
    {
        Console.WriteLine("Service discovered at {0}:{1}",
            ep.Address.ToString(),
            ep.Port.ToString());
        Console.WriteLine(ep.Address.AddressFamily.ToString());
        if (ep.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
        {
            string Url = "net.tcp://" + ep.Address.ToString() + ":" + ep.Port.ToString() +
                "/PhotoService";                       
            NetTcpBinding binding = new NetTcpBinding();
            binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
            binding.MaxReceivedMessageSize = int.MaxValue;
            binding.MaxBufferSize = int.MaxValue;
            EndpointAddress epAddress = new EndpointAddress(Url);
            ChannelFactory<IPhotoService> fact = new ChannelFactory<IPhotoService>(binding,
                                                     epAddress);
            IPhotoService photos = fact.CreateChannel();
            string iconByteString = photos.GetIconBytes();
            byte[] iconBytes = Convert.FromBase64String(iconByteString);
            Console.WriteLine("received {0} image bytes.", iconBytes.Length);                       
            FileStream fs = File.Create(@"C:\" +ep.Address.ToString() +"_" + ep.Port.ToString() + ".png");
            fs.Write(iconBytes, 0, iconBytes.Length);
            fs.Close();
           
         
            service.Icon = @"C:\" + ep.Address.ToString() + "_" + ep.Port.ToString() + ".png";
           
        }
    }
    
    model.DiscoveredServices.Add(service);
  }
}

In short, if you're using WCF and you're using Orcas, you need to give the PNRP stack a look, because being able to dynamically, in a shared, serverless, peer fashion, register the location of services is extremely useful.

tags:        

links: digg this    del.icio.us    technorati    reddit




1. James Gregurich left...
Fri 11 May 07 6:00 pm

Is this a zeroconf implementation that is interoperable with Bonjour?


2. Chris Hanson left...
Sun 13 May 07 12:28 am :: http://chanson.livejournal.com/

It looks a bit like the multicast DNS that Bonjour (nee Rendezvous) is built on. I like the NSNetService APIs better though; they send messages to a delegate upon discovery, making discovery asynchronous. (They've also been part of Cocoa since the release of Mac OS X 10.2 Jaguar in 2002.)

I wonder, why did Microsoft go with something nonstandard when multicast DNS is an open standard and has been around for years? Or are they really supporting it, just under a different name?


3. Kevin Hoffman left...
Sun 13 May 07 2:13 pm

This implementation is (as far as I know) not interoperable with Bonjour. I was trying to be fair and not mention Bonjour in this post because I find Apple's Distributed Objects in conjunction with Bonjour to be far more pleasant to use than WCF and Orcas' PNRP stack.


4. James Gregurich left...
Mon 14 May 07 9:19 am

sad. Microsoft reinvents the wheel again.


5. Kevin Hoffman left...
Mon 14 May 07 10:06 am

What I find hilarious is that this reinvented wheel is handed down from on high and we're all supposed to accept it as if this is the first time anyone has seen multicast/peer2peer DNS before. How old is Rendezvous/Bounjour??


6. Tyler left...
Wed 16 May 07 8:17 pm :: http://blogs.msdn.com/p2p/

PNRP is more than a multicast discovery technology. It does name resolution through an overlay network. You can publish and resolve names through the internet (your laptop at a coffee shop can find your PC at home). Microsoft has a couple of technologies that work like Bonjour: SSDP, WSD and function discovery. PNRP is something completely different. There's a bunch of information on the Microsoft peer-to-peer website if you're interested (www.microsoft.com/p2p).

I hope this helps. There are cool possibilities for PNRP when you start thinking beyond your subnet.

Tyler


Tag Related Posts

Peer Networking Series - What is PNRP?

Wed 30 Apr 08 2:59 P GMT-05

CLINQ v1 Demo - Network Message Filtering

Wed 09 Jan 08 7:47 P GMT-05
tags:        

C# 3.0 - Are Object Initializers Evil, Useful, or Both?

Fri 26 Oct 07 10:53 A GMT-05
tags:    

Continuous LINQ - Can I write games with it?

Mon 13 Aug 07 3:09 P GMT-05
tags:        

Silverlight 1.1 Alpha Refresh

Fri 10 Aug 07 2:09 P GMT-05
tags:    

Orcas Beta 2 - might as well be a CTP

Tue 07 Aug 07 1:15 A GMT-05
tags:  

Dynamic, Observable LINQ Views

Tue 31 Jul 07 1:21 A GMT-05
tags:        

Acropolis or Acrapolis?

Thu 05 Jul 07 12:34 P GMT-05
tags:      

My first "Acropolis" Application

Mon 04 Jun 07 1:40 P GMT-05
tags:      

Orcas' Hidden Gem - The managed PNRP stack

Fri 11 May 07 6:45 P GMT-05
tags:        

Orcas EDM Wizard Patched

Fri 27 Apr 07 11:56 A GMT-05
tags:      

Installing Orcas Beta 1 - VMware Style

Mon 23 Apr 07 12:16 P GMT-05

Orcas Beta 1 Released

Fri 20 Apr 07 7:09 P GMT-05

On MUDs

Thu 08 Mar 07 5:00 A GMT-05
tags:                    

Visual Studio "Orcas" - March CTP is Available

Wed 28 Feb 07 12:28 P GMT-05
tags:            

Objective-C Categories vs C# 3.5 Language Extensions

Mon 26 Feb 07 1:05 P GMT-05
tags:                

What I think is a bug in WCF POX messaging

Thu 04 Jan 07 4:58 P GMT-05
tags:      

Ulysses Agenda Makes Redmond Developer News

Wed 29 Nov 06 7:10 P GMT-05
tags:                

Ulysses Agenda - Network Engine Test 1

Mon 09 Oct 06 2:26 A GMT-05
tags:              

Ulysses Agenda : First Cut Networking Design

Thu 14 Sep 06 12:46 A GMT-05
tags:                  

First Impressions of Windows Vista RC1

Thu 07 Sep 06 1:30 P GMT-05
tags:                      

.NET Framework 3.0 June CTP is out!

Fri 23 Jun 06 6:23 P GMT-05
tags:                

Tech-Ed 2006 - Session Reviews

Tue 13 Jun 06 6:22 P GMT-05
tags: