XAML Playground
about XAML and other Amenities

Writing a server-less conferencing client with Silverlight 4.0 UDP Multicast

2010-01-02T22:42:07+01:00 by Andrea Boschin

When I wrote my article about , I received many questions about writing application that communicate each other with this protocol. The reason for this request is that many people believe that Silverlight being a good platform for game developers due to its great graphical features and its simplicity, so a lot of them want to implement some kind of communication for on-line collaborative games.

Local connections have not been made for this kind of usage because them are available only for communication between application instances running in the same machine and it is not possible to use them to create gaming communications.

With Silverligth 4.0 the System.Net namespace hosts a new kind of socket communications, named UDP Multicast, that seems to be a possible solution for gaming applications but also for applications requiring fast communication between multiple clients, like conferencing applications also with video streaming support.

, also know as IP Multicast, is a well-known protocol that enables the ip infrastructure to replicate messages from multiple sources to be delivered easily to an undefined number of subscribers. The protocol works using a special class of IP addresses (224.0.0.0/4 for ipV4) where each single address represent a group of clients that is communicating each other relying on the network infrastructure for the replication of the messages. This enable the creation of client applications that do not need to have a central server where clients needs to connect using the common TCP sockets.

Like the common UDP protocol, IP Multicast is a not-connected protocol that does not guarantee the arrival of the messages and the order of delivery. So if you need a realiable channel the better is to rely on TCP sockets or you need to implement some kind of consistency check.

Writing a conferencing client

The first example I wrote to test the UDP Multicast feature is a simple conferencing client that enable people to join a multicast group and then send messages to the other members of the group.  The example you can download at the end of the article is very simplified and let the user specify an username (without checking if someone else is using the same username) and join the muklticast group. Then the user can type messages and send them to all the group members.

Silverlight 4.0 has two new classes to implement a multicast client

1) UdpSingleSourceMulticastClient let work with a single well-known source that is the unique client allowed to send to the group. This is the one-to-many communication. You can imagine to write a video source with this class and multiple clients to receive packets from it.

2) UdpAnySourceMulticastClient enables all the clients both to send and receive to or from the multicast group. This let you create something similar to a conferencing application where many-to-many connection is required.

When you use a multicast client the first thing you have to do is to join the group, using the known muticast ip address (ex: 224.0.0.1) and the port (ex: 3000). When the connection have been made you can start send and/or receive from the group. Differently from the TCP sockets with UDPMulticast you do not have a restricted set of ports to use. All the ports above of 1024 are available to the plugin.

Here is a snippet from my UDPAnySourceMulticastChannel I wrote for my example:

   1: public UdpAnySourceMulticastChannel(IPAddress address, int port, int maxMessageSize)
   2: {
   3:     this.ReceiveBuffer = new byte[maxMessageSize];
   4:     this.Client = new UdpAnySourceMulticastClient(address, port);
   5: }
   6:  
   7: public void Open()
   8: {
   9:     if (!this.IsJoined)
  10:     {
  11:         this.Client.BeginJoinGroup(
  12:             result =>
  13:             {
  14:                 this.Client.EndJoinGroup(result);
  15:                 this.IsJoined = true;
  16:                 Deployment.Current.Dispatcher.BeginInvoke(
  17:                     () =>
  18:                     {
  19:                         this.OnAfterOpen();
  20:                         this.Receive();
  21:                     });
  22:             }, null);
  23:     }
  24: }

In the constructor of the class, I've created an instance of the multicast client with the required address and port, then in the Open method I've called the BeginJoinGroup method that starts an asyncronous join request to the multicast address. As always the Silverlight's communication is asyncronous so when the callback is called I need to invoke the EndJoinGroup and then marshal the thread to the user interface with using the Dispatcher.

When the group has been joined you can start receiving and sending. This two actions are simultaneous because while you are receiving messages (or you are waiting to receive) you can also send messages to the group. So you have to invoke the BeginReceiveFromGroup method that starts listening for incoming packets and calls the callback method when something has been received. While the client is waiting for something to receive you can also call the BeginSendToGroup method to send something to the group. You have to be aware that when you send a packet to the group you will also receive the packet you sent because the multicast will replicate the message to all the joined clients.

   1: private void Receive()
   2: {
   3:     if (this.IsJoined)
   4:     {
   5:         Array.Clear(this.ReceiveBuffer, 0, this.ReceiveBuffer.Length);
   6:  
   7:         this.Client.BeginReceiveFromGroup(this.ReceiveBuffer, 0, this.ReceiveBuffer.Length,
   8:             result =>
   9:             {
  10:                 if (!IsDisposed)
  11:                 {
  12:                     IPEndPoint source;
  13:                     this.Client.EndReceiveFromGroup(result, out source);
  14:                     Deployment.Current.Dispatcher.BeginInvoke(
  15:                         () =>
  16:                         {
  17:                             this.OnReceive(source, this.ReceiveBuffer);
  18:                             this.Receive();
  19:                         });
  20:                 }
  21:             }, null);
  22:     }
  23: }
  24:  
  25: public void Send(string format, params object [] args)
  26: {
  27:     if (this.IsJoined)
  28:     {
  29:         byte[] data = Encoding.UTF8.GetBytes(string.Format(format,args));
  30:  
  31:         this.Client.BeginSendToGroup(data, 0, data.Length,
  32:             result =>
  33:             {
  34:                 this.Client.EndSendToGroup(result);
  35:             }, null);
  36:     }
  37: }

The UDPAnySourceMulticastClient class has some other interesting methods. You can send messages to the group specifing the destination so the network infrastructure will route the message to a single target. You can also block and unblock an IPAddress to prevent messages incoming from it to be received.

There is not a "Disconnect" or "Close" method but when you need to end the communication you can call the Dispose method of the client class. This will cause the pending receive to be dropped. It is important to have a flag set when the class is disposing because when the pending receive is dropped your callback is notified and you have to be aware that the client instance is not valid anymore and avoid to call the EndReceiveFromGroup method alse you will get an exception.

   1: /// <summary>
   2: /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
   3: /// </summary>
   4: public void Dispose()
   5: {
   6:     if (!IsDisposed)
   7:     {
   8:         this.IsDisposed = true;
   9:  
  10:         if (this.Client != null)
  11:             this.Client.Dispose();
  12:     }
  13: }

The client needs only to create an instance of the class an then call the Open method to join the multicast group. The channel then automatically starts listening from incoming packets and raise an event every time it detect something. So when the user hit the send button it I can call the Send() method to send a new packet and when the channel notify me about the arrival of a packet I add it to the logging listbox. I've added an AfterOpened and BeforeClose events to allow the client to send a message just after joining the group and before leaving it.

PolicyServer

Like other networking tools in Silverlight, the ip multicast requires something issuing a policy file. This is the sole server-side requirement for this protocol working fine. The policy server has to implement a two UDP messages system. The first message, sent by the client, is a datagram called "announcement" that asks the server to issue a policy file. When the server receive this message have to send an xml file that authorize to the client to communicate with a particular ip address and port. The mechanism is very similar to the TCP socket policy server but use an UDP messagging system.

To implement this server the best is downloading this project from MSDN code gallery. The project contains a working policy server that you can simply start from a console application or from a win32 service.

The drawbacks

The application I have included at the end of the article is very simple and demostrate the power of this messaging system, that was initially designed for effective video streaming. Unfortunately there is some drawbacks. First of all, also if I've entitled this example "server-less" this is true for the 99%. You need a policy issuer that is a little server, but it is not crucial for performance concerns. The system is really simpler than an always-connected TCP implementation and due to the nature of the UDP protocol really require less resources.

Another concern is about the security and realiability. The UDP protocol does not implements some infrastructure to avoid the ip spoofing and does not guarantee the packet delivery and the arrival order. In a real world solution you have to be aware of these limitation and take care of them. You have to write code to sign packets to know from whom they are issued and to handle packet loss and unordered delivery. This may be someway complex, but is a little price to pay for the effectiveness of this protocol.

Finally, the major drawback is that the most common firewalls manage to block this kind of traffic. If using a TCP socket server on a well known port is someway difficult due to the need of having firewall configurations, implementing a multicast is probably more complex specifically if you need to send the packets through the Internet. So in my opinion the most common scenario for this protocol to work is a local area network where you can manage to have firewalls and network infrastructure comply with it.

Download: SilverlightPlayground.UDPMulticast.zip (181 KB)

Categories:   Networking
Actions:   E-mail | del.icio.us | Permalink | Comments (1) | Comment RSSRSS comment feed

Comments (1) -

March 17. 2010 13:06

Andrea, thanks a lot for this interesting topic.
It works fine for me, when I was using only one PC. I could simultaneously open any number of browsers and chat between them.
Than, I've connected my friend's laptop to my network with lynksis router via Wi-Fi. Silverlight application was running good, but I couldn't chat because a SocketException was thrown with SocketError AccessDenied on friend's laptop.

What i've done for trying this:
set MulticastPolicyConfiguration to AnySourceConfiguration in SilverlightPlayground.UDPMulticast.PolicyServer and allow my local ip(192.168.1.104), where application was running.

After that, i've just run SilverlightPlayground.UDPMulticast.PolicyServer on 192.168.1.104 and congigured my IIS to run SilverlightPlayground.UDPMulticast.Web on 192.168.1.104

So, when i go to http://192.168.1.104 from my computer it works fine, but when i go from friend's comp (192.168.1.105) I have socketexception.

What have I missed? Why isn't it working?
Thanks for reply.

Vlad