|
C# Multicast Program Example
Create a new console application project and you might use MulticastCS as the name.
|
Add/edit the following using directives at the top of the file.
using System; using System.Collections; using System.Net; using System.Net.Sockets; |
Next, rename the class to MulticastEndpoint.
Add the following code for the MulticastEndpoint class.
class MulticastEndpoint { public ArrayList localInterfaceList, multicastJoinList; public Socket mcastSocket; public IPAddress bindAddress; public int bufferSize; public int localPort; public byte [ ] dataBuffer;
/// <summary> /// Simple constructor for the /// </summary> public MulticastEndpoint() { localInterfaceList = new ArrayList(); multicastJoinList = new ArrayList(); bufferSize = 512; mcastSocket = null; }
/// <summary> /// This method creates the socket, joins it to the given multicast groups, and initializes /// the send/receive buffer. Note that the local bind address should be the wildcard address /// because it is possible to join multicast groups on one or more local interface and if /// a socket is bound to an explicit local interface, it can lead to user confusion (although /// this does currently work on Windows OSes). /// </summary> /// <param name="port">Local port to bind socket to</param> /// <param name="bufferLength">Length of the send/recv buffer to create</param> public void Create(int port, int bufferLength) { localPort = port;
Console.WriteLine("Creating socket, joining multicast group and"); Console.WriteLine(" initializing the send/receive buffer"); try { // If no bind address was specified, pick an appropriate one based on the multicast // group being joined. if ( bindAddress == null ) { IPAddress tmpAddr = (IPAddress) multicastJoinList[0];
if ( tmpAddr.AddressFamily == AddressFamily.InterNetwork ) bindAddress = IPAddress.Any; else if ( tmpAddr.AddressFamily == AddressFamily.InterNetworkV6 ) bindAddress = IPAddress.IPv6Any; }
// Create the UDP socket Console.WriteLine("Creating the UDP socket..."); mcastSocket = new Socket( bindAddress.AddressFamily, SocketType.Dgram, 0 );
Console.WriteLine("{0} multicast socket created", bindAddress.AddressFamily.ToString());
// Bind the socket to the local endpoint Console.WriteLine("Binding the socket to the local endpoint..."); IPEndPoint bindEndPoint = new IPEndPoint( bindAddress, port ); mcastSocket.Bind( bindEndPoint ); Console.WriteLine("Multicast socket bound to: {0}", bindEndPoint.ToString());
// Join the multicast group Console.WriteLine("Joining the multicast group..."); for(int i = 0; i < multicastJoinList.Count ;i++) { for(int j = 0; j < localInterfaceList.Count ;j++) { // Create the MulticastOption structure which is required to join the // multicast group if ( mcastSocket.AddressFamily == AddressFamily.InterNetwork ) { MulticastOption mcastOption = new MulticastOption( (IPAddress) multicastJoinList[i], (IPAddress) localInterfaceList[j] );
mcastSocket.SetSocketOption( SocketOptionLevel.IP, SocketOptionName.AddMembership, mcastOption ); } else if ( mcastSocket.AddressFamily == AddressFamily.InterNetworkV6 ) { IPv6MulticastOption ipv6McastOption = new IPv6MulticastOption( (IPAddress) multicastJoinList[i], ( (IPAddress) localInterfaceList[j] ).ScopeId );
mcastSocket.SetSocketOption( SocketOptionLevel.IPv6, SocketOptionName.AddMembership, ipv6McastOption ); }
Console.WriteLine("Joined multicast group {0} on interface {1}", multicastJoinList[i].ToString(), localInterfaceList[j].ToString() ); } }
// Allocate the send and receive buffer Console.WriteLine("Allocating the send and receive buffer..."); dataBuffer = new byte [ bufferLength ]; } catch ( SocketException err ) { Console.WriteLine("Exception occurred when creating multicast socket: {0}", err.Message); throw; } }
/// <summary> /// This method drops membership to any joined groups. To do so, you have to /// drop the group exactly as you joined it -- that is the local interface /// and multicast group must be the same as when it was joined. Also note /// that it is not required to drop joined groups before closing a socket. /// When a socket is closed all multicast joins are dropped for you -- this /// routine just illustrates how to drop a group if you need to in the middle /// of the lifetime of a socket. /// </summary> public void LeaveGroups() { try { Console.WriteLine("Dropping membership to any joined groups..."); for(int i = 0; i < multicastJoinList.Count ;i++) { for(int j = 0; j < localInterfaceList.Count ;j++) { // Create the MulticastOption structure which is required to drop the // multicast group (the same structure used to join the group is // required to drop it). if ( mcastSocket.AddressFamily == AddressFamily.InterNetwork ) { MulticastOption mcastOption = new MulticastOption( (IPAddress) multicastJoinList[i], (IPAddress) localInterfaceList[j] );
mcastSocket.SetSocketOption( SocketOptionLevel.IP, SocketOptionName.DropMembership, mcastOption ); } else if ( mcastSocket.AddressFamily == AddressFamily.InterNetworkV6 ) { IPv6MulticastOption ipv6McastOption = new IPv6MulticastOption( (IPAddress) multicastJoinList[i], ( (IPAddress) localInterfaceList[j] ).ScopeId );
mcastSocket.SetSocketOption( SocketOptionLevel.IPv6, SocketOptionName.DropMembership, ipv6McastOption ); }
Console.WriteLine("Dropping multicast group {0} on interface {1}", multicastJoinList[i].ToString(), localInterfaceList[j].ToString() ); } } } catch { Console.WriteLine("LeaveGroups: No multicast groups joined"); } }
/// <summary> /// This method sets the outgoing interface when a socket sends data to a multicast /// group. Because multicast addresses are not routable, the network stack simply /// picks the first interface in the routing table with a multicast route. In order /// to change this behavior, the MulticastInterface option can be used to set the /// local interface on which all outgoing multicast traffic is to be sent (for this /// socket only). This is done by converting the 4 byte IPv4 address (or 16 byte /// IPv6 address) into a byte array. /// </summary> /// <param name="sendInterface"></param> public void SetSendInterface( IPAddress sendInterface ) { // Set the outgoing multicast interface try { Console.WriteLine("Setting the outgoing multicast interface..."); if ( mcastSocket.AddressFamily == AddressFamily.InterNetwork ) { mcastSocket.SetSocketOption( SocketOptionLevel.IP, SocketOptionName.MulticastInterface, sendInterface.GetAddressBytes() ); } else { byte [ ] interfaceArray = BitConverter.GetBytes( (int)sendInterface.ScopeId );
mcastSocket.SetSocketOption( SocketOptionLevel.IPv6, SocketOptionName.MulticastInterface, interfaceArray ); } Console.WriteLine("Setting multicast send interface to: " + sendInterface.ToString()); } catch ( SocketException err ) { Console.WriteLine("SetSendInterface: Unable to set the multicast interface: {0}", err.Message); throw; } }
/// <summary> /// This method takes a string and repeatedly copies it into the send buffer /// to the length of the send buffer. /// </summary> /// <param name="message">String to copy into send buffer</param> public void FormatBuffer( string message ) { byte [ ] byteMessage = System.Text.Encoding.ASCII.GetBytes( message ); int index = 0;
// First convert the string to bytes and then copy into send buffer Console.WriteLine("Formatting the send buffer..."); while ( index < dataBuffer.Length ) { for(int j=0; j < byteMessage.Length ;j++) { dataBuffer[ index ] = byteMessage[ j ]; index++;
// Make sure we don't go past the send buffer length if ( index >= dataBuffer.Length ) { break; } } } } } |
Next, add another class and name it MulticastSample. The Main() is in this class.
class MulticastSample { /// <summary> /// This method prints usage information for multicast sample /// </summary> static void usage() { Console.WriteLine("Executable_file_name [/i ip] [/b ip] [/m ip] [/p port] [/x num] [/t text]"); Console.WriteLine(" [/n count] [/s | /r]"); Console.WriteLine("Available options:"); Console.WriteLine(" /i ip Local interface to join multicast group(s) on"); Console.WriteLine(" /b ip Local IP to bind the socket to"); Console.WriteLine(" /m ip Multicast group to join"); Console.WriteLine(" /p port Port to listen on or send to"); Console.WriteLine(" /x size Length of send or receive buffer"); Console.WriteLine(" /t text Text message to put in send buffer"); Console.WriteLine(" /n count Number of times to send or receive"); Console.WriteLine(" /s Send data to a multicast group"); Console.WriteLine(" /r Receive data send to the group"); Console.WriteLine(); }
/// <summary> /// This is the main routine which parses the command line and creates the /// multicast socket as given by the command line parameters. The sample /// can either be invoked as a multicast sender or receiver. /// /// To invoke as a multicast receiver: /// multicast.exe /r /i 10.10.10.1 /m 234.6.6.6 /// To invoke as a multicast sender: /// multicast.exe /s /i 10.10.10.99 /m 234.6.6.6 /// </summary> /// <param name="appArguments">Command line arguments</param> static void Main(string[] appArguments) { MulticastEndpoint mcastEndpoint = new MulticastEndpoint(); string textMessage = "Hello Bastard World"; int port = 0, bufferLength = 1024, opCount = 10; bool isSender = true;
// Parse the command line for (int i = 0; i < appArguments.Length; i++) { try { if ((appArguments[i][0] == '-') || (appArguments[i][0] == '/')) { switch (Char.ToLower(appArguments[i][1])) { case 'b': // Address to bind multicast socket to mcastEndpoint.bindAddress = IPAddress.Parse(appArguments[++i]); break; case 'c': // How many times to send or receive opCount = System.Convert.ToInt32(appArguments[++i].ToString()); break; case 'i': // Local interface to join group(s) on mcastEndpoint.localInterfaceList.Add(IPAddress.Parse(appArguments[++i])); break; case 'm': // Multicast group to join mcastEndpoint.multicastJoinList.Add(IPAddress.Parse(appArguments[++i])); break; case 'p': // Port number to bind to or send to port = System.Convert.ToInt32(appArguments[++i].ToString()); break; case 'r': // Application invoked as receiver isSender = false; break; case 's': // Application invoked as sender isSender = true; break; case 't': // Text message to send textMessage = appArguments[++i]; break; case 'x': // Length of send/receive buffer bufferLength = System.Convert.ToInt32(appArguments[++i].ToString()); break; default: usage(); return; } } } catch { usage(); return; } }
// Make sure user specified at least on multicast group and interface to join if ((mcastEndpoint.multicastJoinList.Count == 0) || (mcastEndpoint.localInterfaceList.Count == 0)) { Console.WriteLine("Please specify a multicast group and interface to join on!"); usage(); return; }
// Now, create the multicast socket Console.WriteLine("Creating the multicast socket..."); try { if (isSender == true) { // For the sender, we don't care what the local port the socket is bound to mcastEndpoint.Create( 0, // If the sender we don't care what local port we bind to bufferLength ); } else { mcastEndpoint.Create(port, bufferLength); }
if (isSender == true) { IPEndPoint destinationGroup = new IPEndPoint((IPAddress)mcastEndpoint.multicastJoinList[0], port); int rc;
// Set the send interface for all outgoing multicast packets Console.WriteLine("Setting the send interface for all outgoing multicast packets..."); mcastEndpoint.SetSendInterface((IPAddress)mcastEndpoint.localInterfaceList[0]); mcastEndpoint.FormatBuffer(textMessage);
// Send the message the requested number of times Console.WriteLine("Sending the message the requested number of times..."); for (int i = 0; i < opCount; i++) { try { rc = mcastEndpoint.mcastSocket.SendTo(mcastEndpoint.dataBuffer, destinationGroup); Console.WriteLine("Multicast SendTo() is OK..."); Console.WriteLine("Sent {0} bytes to {1}", rc, destinationGroup.ToString()); } catch (SocketException err) { Console.WriteLine("Multiast SendTo() failed: " + err.Message); } } } else { IPEndPoint senderEndPoint = new IPEndPoint((IPAddress)mcastEndpoint.localInterfaceList[0], 0); EndPoint castSenderEndPoint = (EndPoint)senderEndPoint; int rc;
for (int i = 0; i < opCount; i++) { try { rc = mcastEndpoint.mcastSocket.ReceiveFrom(mcastEndpoint.dataBuffer, ref castSenderEndPoint); Console.WriteLine("Multicast ReceiveFrom() is OK..."); senderEndPoint = (IPEndPoint)castSenderEndPoint; Console.WriteLine("Received {0} bytes from {1}: '{2}'", rc, senderEndPoint.ToString(), System.Text.Encoding.ASCII.GetString(mcastEndpoint.dataBuffer, 0, rc) ); } catch (SocketException err) { Console.WriteLine("Multicast ReceiveFrom() failed: " + err.Message); } } }
// Drop membership to groups. This isn't required in this sample as closing the socket // will implicitly leave all groups joined, but it's a good practice. mcastEndpoint.LeaveGroups(); } catch { Console.WriteLine("An error occurred creating the multicast socket"); } finally { if (mcastEndpoint.mcastSocket != null) { Console.WriteLine("Closing the multicast socket..."); mcastEndpoint.mcastSocket.Close(); } mcastEndpoint = null; } } } |
Build the project and make sure there is no error.
Run the project. Any error will be thrown by the exception handlers.
![]() |
|
The following is the sample output.
The following are sample outputs for sender and receiver when run from the command prompt. This program example was tested on a simple private network with two computers connected using the peer-to-peer cable (cross cable). You may want to test on the real network with more receivers that will resemble the chat system. Firstly, we run the receiver.
Then, we run the sender.
The following is the receiver output screenshot when the communication was completed.