C# IP Multicast Support



C# IP Multicast Support

The .NET network library supports IP multicasting by using Socket options. Once a Socket object is created, it can be set to join a multicast group or to leave a multicast group that it has previously joined. This technique is used for UdpClient objects, as well.

C# Socket Multicasting

The Socket class supports IP multicasting by using the SetSocketOption() method of the socket, but in a different way than with broadcasting.

There are two socket options that can be used for multicasting:

  • Adding the socket to a multicast group

  • Removing the socket from a multicast group

Both of these options are defined by IP-level Socket option names, AddMembership and DropMembership.

The value parameter of the SetSocketOption() method is not a normal data value. Instead, it uses the MulticastOption class.

The MulticastOption class defines the multicast group that the socket will be added to or removed from. These two constructors are used for the MulticastOption class:

MulticastOption(IPAddress)
MulticastOption(IPAddress,IPAddress)

The firsts constructor format defines the IP multicast address used in the SetSocketOption. The default behavior of this constructor is to allow all interfaces on the system to be affected by the SetSocketOption() method. If you want to limit the action to an individual network interface on the system, the second constructor allows specification of an IPAddress value to represent the interface.

For example, if you wanted to add a socket to the multicast group 224.100.0.1, you would use the following statement:

sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership,
   new MulticastOption(IPAddress.Parse("224.100.0.1"));

This sets the socket to join the multicast group for all interfaces on the system.

Receiving Multicast Packets

The MultiRecv.cs program in Listing 10.6 sets a socket to receive multicast packets destined for the 224.100.0.1 multicast group.

Listing 10.6: The MultiRecv.cs program
Start example
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class MultiRecv
{
  public static void Main()
  {
   Socket sock = new Socket(AddressFamily.InterNetwork,
                SocketType.Dgram, ProtocolType.Udp);
   Console.WriteLine("Ready to receive…");
   IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9050);
   EndPoint ep = (EndPoint)iep;
   sock.Bind(iep);
   sock.SetSocketOption(SocketOptionLevel.IP, Â
   SocketOptionName.AddMembership, Â
   new MulticastOption(IPAddress.Parse("224.100.0.1")));
   byte[] data = new byte[1024];
   int recv = sock.ReceiveFrom(data, ref ep);
   string stringData = Encoding.ASCII.GetString(data, 0, recv);
   Console.WriteLine("received: {0} from: {1}", stringData, ep.ToString());
   sock.Close();
  }
}
End example

The MultiRecv program creates a UDP socket in the normal way, using the standard Socket class methods. After being added to the multicast group, the socket blocks on a ReceiveFrom() method call, waiting for data to arrive.

Some Cautions about Multicast Sockets

There are two very important points to remember about using multicast sockets:

First, the SetSocketOption() method call must be made after the Bind() method call for the socket. This enables the multicast group to be set for a specific IPEndPoint address on the socket.

Second, once the socket has been added to a multicast group, the ReceiveFrom() method will accept packets destined for the following:

  • The IPEndPoint address and port specified in the Bind() method

  • The multicast group IP address specified in the MulticastOption constructor and the port specified in the IPEndPoint object

  • Broadcast packets for the specified IPEndPoint port

Many novice network programmers forget the second item, especially. When a ReceiveFrom() method is performed, you are not guaranteed to receive packets destined just for the multicast group. So be careful of extraneous packets sent from other sources. You will not be able to easily distinguish those packets.

Sending Multicast Packets

Sending multicast packets is easy. Nothing special must be done to send the packets to members in the multicast group; you just specify the multicast group IP address as the destination address of the packet. Listing 10.7 demonstrates this with the MultiSend.cs program.

Listing 10.7: The MultiSend.cs program
Start example
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class MultiSend
{
  public static void Main()
  {
   Socket server = new Socket(AddressFamily.InterNetwork,
           SocketType.Dgram, ProtocolType.Udp);
   IPEndPoint iep = new IPEndPoint(IPAddress.Parse("224.100.0.1"), 9050);
   
   byte[] data = Encoding.ASCII.GetBytes("This is a test message");
   server.SendTo(data, iep);
   server.Close();
  }
}
End example

Note that nowhere is the SetSocketOption() used on the socket. It is unnecessary if the socket will only send packets to the multicast group on the local subnet. As you will see later, if you want to forward multicast packets to other networks, you will have to use the SetSocketOption(). Also, if the socket needs to receive multicast packets, the SetSocketOption() must be used with the appropriate MulticastOption constructor for the multicast group.

Watching the Programs

You can test these programs on your system and watch the network traffic using WinDump or Analyzer. In this case, because the MulticastOption constructor did not specify an interface, you can watch the network packets even if both the sender and receiver are running on the same machine.

First, start the MultiRecv program in a command prompt window. Then run the MultiSend program in a second command prompt window. You should see the following text, along with the address of the sending machine, displayed in the MultiRecv console:

C:\>MultiRecv
received: This is a test message from: 192.168.1.6:1294
C:\>

What is even more interesting is the trace file from running MultiSend and MultiRecv. Listing 10.8 shows a sample output from the WinDump program.

Listing 10.8: Sample WinDump output from the multicast test
Start example
C:\>windump -X ip host 158.18.125.32
windump    listening on\Device\Packet_El90x1
09:05:20.776334 158.18.125.32 > 224.100.0.1: 158.18.125.32 > 224.100.0.1: igmp v
2 report 224.100.0.1 [ttl 1]
0x0000  4600 0020 f613 0000 0102 332c 9e12 7d20    F.........3,..}.
0x0010  e064 0001 9404 0000 1600 099a e064 0001    .d...........d..
09:05:24.357183 158.18.125.32 > 224.100.0.1: 158.18.125.32 > 224.100.0.1: igmp v
2 report 224.100.0.1 [ttl 1]
0x0000  4600 0020 fc13 0000 0102 2d2c 9e12 7d20    F.........-,..}.
0x0010  e064 0001 9404 0000 1600 099a e064 0001    .d...........d..
09:05:28.433814 158.18.125.32.1502 > 224.100.0.1.9050: udp 22 [ttl 1]
0x0000  4500 0032 0114 0000 0111 bd0f 9e12 7d20    E..2..........}.
0x0010  e064 0001 05de 235a 001e dfda 5468 6973    .d....#Z....This
0x0020  2069 7320 6120 7465 7374 206d 6573 7361    .is.a.test.messa
0x0030  6765                      ge
09:05:28.435433 158.18.125.32 > ALL-ROUTERS.MCAST.NET: 158.18.125.32 > ALL-ROUTE
RS.MCAST.NET: igmp leave 224.100.0.1 [ttl 1]
0x0000  4600 0020 0214 0000 0102 278f 9e12 7d20    F.........'...}.
0x0010  e000 0002 9404 0000 1700 089a e064 0001    .............d..
289 packets received by filter
0 packets dropped by kernel
C:\>
End example

When the MultiRecv program started, it sent two IGMP packets on the network destined for the multicast group address. These were not sent as part of the program methods. They were automatically sent by the .NET network library functions.

The IGMP packets are intended to notify any routers on the network that the device intends to join the multicast group, and that any packets with that multicast group address should be forwarded to the subnet. After the IGMP packets go out, the MultiSend program sends its UDP packet with the test message, as expected, using the multicast group address as the destination.

When the MultiRecv program closes the Socket object, another IGMP packet is sent on the network to indicate the device is leaving the multicast group. You may notice that this packet is not sent to the multicast group address but is instead sent to an address specified as ALL-ROUTERS.MCAST.NET. This is the multicast address 224.0.0.2, which is a special router control multicast group. This packet informs any routers on the local network that they no longer have to forward multicast group packets for this device.

The Multicast TTL Value

If you look closely at the multicast packet sent out from the MultiSend program, you may notice that it has a TTL value of 1. With this value, the TCP packet will not be allowed to be forwarded by a router. This indicates that the Socket class by default allows the socket to send messages to the multicast group, but it restricts it to the local subnet. To send multicast packets that can traverse multiple routers, you must increase the TTL value of the multicast packet. This can be done with the SetSocketOption() method, but things get considerably more complicated.

As with receiving multicast sockets, to use the SetSocketOption() method you must bind the socket to a local IPEndPoint object, indicate that the socket will be used for multicasting, and then set the new TTL value. It looks like this:

Socket sock = new Socket(AddressFamily.InterNetwork,
             SocketType.Dgram, ProtocolType.Udp);
IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9050);
sock.Bind(iep);
sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership,
   new MulticastOption(IPAddress.Parse("224.100.0.1")));
sock.SetSocketOption(SocketOptionLevel.IP,
   SocketOptionName.MulticastTimeToLive, 50);

Now the socket is added to the multicast group, and its TTL value is changed to 50 hops.

Using this concept, the NewMultiSend.cs program in Listing 10.9 is created to send multicast packets across network boundaries.

Listing 10.9: The NewMultiSend.cs program
Start example
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class NewMultiSend
{
  public static void Main()
  {
   Socket server = new Socket(AddressFamily.InterNetwork,
                 SocketType.Dgram, ProtocolType.Udp);
   IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9051);
   IPEndPoint iep2 = new IPEndPoint(IPAddress.Parse("224.100.0.1"), 9050);
   server.Bind(iep);
   
   byte[] data = Encoding.ASCII.GetBytes("This is a test message");
   server.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership,
               new MulticastOption(IPAddress.Parse("224.100.0.1")));
   server.SetSocketOption(SocketOptionLevel.IP,
   SocketOptionName.MulticastTimeToLive, 50);
   server.SendTo(data, iep2);
   server.Close();
  }
}
End example

Now when the multicast packet is sent out, it has a TTL value of 50, allowing it to traverse up to 50 hops before it is terminated. You can use the MultiRecv program to watch the multicast packet go out on the network. You can also view the packet using the WinDump or Analyzer programs.

C# UdpClient Multicasting

The .NET UdpClient class also supports IP multicast group addresses. The UdpClient class uses specific methods to allow the socket to join a multicast group or be removed from a multicast group. The following two methods are used:

  • JoinMulticastGroup()

  • DropMulticastGroup()

As you’d expect, the JoinMulticastGroup() method allows the socket to receive messages destined for a particular multicast group address. This method can be created using one of two formats:

JoinMulticastGroup(IPAddress)
JoinMulticastGroup(IPAddress, int)

The first constructor allows the socket to join the multicast group specified by the IPAddress object. The second constructor format lets you include a TTL value to the socket, enabling it to receive multicast packets sent from more distant hosts.

Here’s an example code snippet using the UdpClient multicast methods:

UdpClient uc = new UdpClient(9050);
uc.JoinMulticastGroup(IPAddress.Parse("224.100.0.1"));
Warning 

Remember to use a default UDP port number in the UdpClient constructor. If you do not include a port number, the JoinMulticastGroup() method will fail because it does not know for what port to accept multicast messages.

UdpClient Multicast Receiver

The UdpClientMultiRecv program in Listing 10.10 demonstrates the programming for joining a UdpClient object to a multicast group and receiving packets from the group.

Listing 10.10: The UdpClientMultiRecv.cs program
Start example
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class UdpClientMultiRecv
{
  public static void Main()
  {
   UdpClient sock = new UdpClient(9050);
   Console.WriteLine("Ready to receive…");
   sock.JoinMulticastGroup(IPAddress.Parse("224.100.0.1"), 50);
   IPEndPoint iep = new IPEndPoint(IPAddress.Any, 0);
   byte[] data = sock.Receive(ref iep);
   string stringData = Encoding.ASCII.GetString(data, 0, data.Length);
   Console.WriteLine("received: {0} from: {1}", stringData, iep.ToString());
   sock.Close();
  }
}
End example

Nothing too fancy here. You’re just creating a simple UdpClient object and using the JoinMulticastGroup() method to allow it to accept messages destined for the 224.100.0.1 multicast group address. After the first message is received, the socket is closed and the program terminates.

UdpClient Multicast Sender

Similar to the Socket class, the UdpClient class does not need any special methods to send packets to a multicast group address. Just follow the standard UdpClient procedures to send a message to the specific IP address. Listing 10.11 shows the UdpClientMultiSend.cs program, which demonstrates sending a message to a multicast group address using the UdpClient class.

Listing 10.11: The UdpClientMultiSend.cs program
Start example
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class UdpClientMultiSend
{
  public static void Main()
  {
   UdpClient sock = new UdpClient();
   IPEndPoint iep = new IPEndPoint(IPAddress.Parse("224.100.0.1"), 9050);
   byte[] data = Encoding.ASCII.GetBytes("This is a test message");
   sock.Send(data, data.Length, iep);
   sock.Close();
  }
}
End example

Testing the Programs

Like the Socket versions of the multicasting programs, you can test the UdpClient versions by first starting the UdpClientMultiRecv program in a command prompt window and then running the UdpClientMultiSend program. You should see the test message appear in the UdpClientMultiRecv program’s console.

Because the traffic is sent out all the interfaces, you can monitor it using WinDump or Analyzer. Listing 10.12 shows the output from the WinDump trace. Just like the Socket class, the UdpClient class sends out two IGMP packets to inform local routers that the device wants to join the multicast group. The rest of the behavior of the program is exactly the same as the Socket version.

Listing 10.12: The WinDump output from the UdpClient multicast test
Start example
C:\>windump -X ip host 158.18.125.32
windump    listening on\Device\Packet_El90x1
10:52:19.653155 158.18.125.32 > 224.100.0.1: 158.18.125.32 > 224.100.0.1: igmp v
2 report 224.100.0.1 [ttl 1]
0x0000  4600 0020 f922 0000 0102 301d 9e12 7d20    F...."....0...}.
0x0010  e064 0001 9404 0000 1600 099a e064 0001    .d...........d..
10:52:21.615597 158.18.125.32 > 224.100.0.1: 158.18.125.32 > 224.100.0.1: igmp v
2 report 224.100.0.1 [ttl 1]
0x0000  4600 0020 fc22 0000 0102 2d1d 9e12 7d20    F...."....-...}.
0x0010  e064 0001 9404 0000 1600 099a e064 0001    .d...........d..
10:52:23.101905 158.18.125.32.1718 > 224.100.0.1.9050: udp 22 [ttl 1]
0x0000  4500 0032 fe22 0000 0111 c000 9e12 7d20    E..2."........}.
0x0010  e064 0001 06b6 235a 001e df02 5468 6973    .d....#Z....This
0x0020  2069 7320 6120 7465 7374 206d 6573 7361    .is.a.test.messa
0x0030  6765                      ge
10:52:23.104539 158.18.125.32 > ALL-ROUTERS.MCAST.NET: 158.18.125.32 > ALL-ROUTE
RS.MCAST.NET: igmp leave 224.100.0.1 [ttl 1]
0x0000  4600 0020 ff22 0000 0102 2a80 9e12 7d20    F...."....*...}.
0x0010  e000 0002 9404 0000 1700 089a e064 0001    .............d..
329 packets received by filter
0 packets dropped by kernel
C:\>
End example

 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows