How to send and receive data in a multicast group for Windows Phone 8

[ This article is for Windows Phone 8 developers. If you’re developing for Windows 10, see the latest documentation. ]

 

This topic demonstrates how to communicate over a multicast group. Multicast traffic is a scalable method for many-to-many communication on the Internet. Communication occurs within multicast groups, each identified by an IP address known as a multicast group address. A device subscribes to a multicast group address. Then, any packets sent by a subscribed device to the multicast group are received by every other device subscribed to the multicast address. This topic introduces you to the steps necessary to join a multicast group in Windows Phone OS 7.1 using the UdpAnySourceMulticastClient class available in the System.Net.Sockets namespace. A completed sample of an app that demonstrates this functionality is available for download. For more information, see Multicast Sockets Sample.

This topic contains the following sections.

 

Creating the UI

In this section, you create the UI for demonstrating the UDP Multicast functionality. This is a Windows Phone app. When the app starts, it joins a multicast group. After the app joins the group, it receives messages sent to the multicast group and can also send messages to the multicast group. The UI will display all data sent to the multicast group. You can also type in a message and send it to the multicast group.

To create the UI

  1. In Visual Studio, create a new project by selecting the File | New Project menu command.

  2. The New Project window is displayed. Expand the Visual C# templates, and then select the Windows Phone templates.

  3. Select the **Windows Phone App ** template. Fill in the Name with a name of your choice.

  4. Click OK. The Windows Phone platform selection dialog box appears. Select a target version, or accept the default.

  5. Click OK. A new project is created, and MainPage.xaml is opened in the Visual Studio designer window.

  6. On MainPage.xaml, remove the XAML code for the Grid named “LayoutRoot” and replace it with the following code.

         <Grid x:Name="LayoutRoot" Background="Transparent">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
    
            <!--TitlePanel contains the name of the application and page title-->
            <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
                <TextBlock x:Name="ApplicationTitle" Text="BasicUDPMulticastClient" 
                           Style="{StaticResource PhoneTextNormalStyle}"/>
                <TextBlock x:Name="PageTitle" Text="messages" Margin="9,-7,0,0" 
                           Style="{StaticResource PhoneTextTitle1Style}"/>
            </StackPanel>
    
            <!--ContentPanel - place additional content here-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="500"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <ListBox x:Name="lbLog" Height="500" 
                         BorderBrush="{StaticResource PhoneForegroundBrush}" BorderThickness="5" 
                         Background="{StaticResource PhoneDisabledBrush}" />
                <StackPanel Grid.Row="1" Orientation="Horizontal">
                    <TextBlock Text="Text To Send" VerticalAlignment="Center"/>
                    <TextBox x:Name="txtInput" Width="200"/>
                    <Button x:Name="btnSend" Width="150" Content="Send" Click="btnSend_Click"/>
                </StackPanel>
            </Grid>
        </Grid>
    

    The preceding XAML code creates a simple user interface that looks like the following screenshot.

    The event handler btnSend_Click is described in the following section.

  7. To send data to the multicast group, the app uses a TextBox to accept some text from the user and a button that, when clicked, will send the text in the TextBox to the multicast group. The btnSend_Click event will fire and we add an event handler to the code-behind file to handle this event. In Solution Explorer, right-click MainPage.xaml and then click View Code. The code-behind file opens in the code editor. At the top of the code-behind file for your page, add the following method:

            /// <summary>
            /// Send whatever the user has typed into the input textbox to the multicast group.
            /// </summary>
            private void btnSend_Click(object sender, RoutedEventArgs e)
            {
                // Don't send empty messages.
                if (!String.IsNullOrWhiteSpace(txtInput.Text))
                {
                    Send(txtInput.Text);
                }
            }
    

    This method first makes sure that the input text box contains some text and then sends the data to the multicast group by calling the Send method, passing in the text to be sent. The Send method is described in the following sections.

  8. To display messages being sent and received in the multicast group, the user interface contains a ListBox called lbLog. The following code is used to add the messages received to the ListBox. In Solution Explorer, right-click MainPage.xaml and then click View Code. The code-behind file opens in the code editor. At the top of the code-behind file for your page, add the following method.

            /// <summary>
            /// Log text to the lbLog ListBox.
            /// </summary>
            /// <param name="message">The message to write to the lbLog ListBox</param>
            /// <param name="isOutgoing">True if the message is an outgoing (client to server) message; otherwise, False</param>
            /// <remarks>We differentiate between a message from the client and server 
            /// by prepending each line  with ">>" and "<<" respectively.</remarks>
            private void Log(string message, bool isOutgoing)
            {
                if (string.IsNullOrWhiteSpace(message.Trim('\0')))
                    return;
    
                // Always make sure to do this on the UI thread.
                Deployment.Current.Dispatcher.BeginInvoke(
                () =>
                {
                    string direction = (isOutgoing) ? ">> " : "<< ";
                    string timestamp = DateTime.Now.ToString("HH:mm:ss");
                    message = timestamp + direction + message;
                    lbLog.Items.Add(message);
    
                    // Make sure that the item we added is visible to the user.
                    lbLog.ScrollIntoView(message);
                });
    
            }
    

    The preceding method accepts a message string and an indication of whether the message being logged is considered an incoming message to this device, or an outgoing message, that is, a message that this device sent. This message is modified to contain a direction indicator and a timestamp. It is then added to the list box and scrolled into view so that the user can see the last message logged at all times. All these UI operations are wrapped in a BeginInvoke to guarantee that they are always executed on the UI thread. This is a safety precaution since this example contains asynchronous operations that will run on a different thread than the UI thread.

Joining a multicast group

In this section, you join a multicast group so that you can send and receive data in that group.

To join a multicast group

  1. In Solution Explorer, right-click MainPage.xaml and then click View Code. The code-behind file opens in the code editor. At the top of the code-behind file for your page, add the following statements:

    using System.Net.Sockets;
    using System.Text;
    
  2. At the top of the MainPage class, define the following members.

            // The address of the multicast group to join.
            // Must be in the range from 224.0.0.0 to 239.255.255.255
            private const string GROUP_ADDRESS = "224.0.1.1";
    
            // The port over which to communicate to the multicast group
            private const int GROUP_PORT = 52274;
    
            // A client receiver for multicast traffic from any source
            UdpAnySourceMulticastClient _client = null;
    
            // true if we have joined the multicast group; otherwise, false
            bool _joined = false;
    
            // Buffer for incoming data
            private byte[] _receiveBuffer;
    
            // Maximum size of a message in this communication
            private const int MAX_MESSAGE_SIZE = 512;
    

    The following points should be noted about the preceding code:

    • GROUP_ADDRESS: A multicast group is defined by a multicast group address, which is an IP address that must be in the range from 224.0.0.0 to 239.255.255.255. Multicast addresses in the range from 224.0.0.0 to 224.0.0.255 inclusive are “well-known” reserved multicast addresses. For example, 224.0.0.0 is the Base address, 224.0.0.1 is the multicast group address that represents all systems on the same physical network, and 224.0.0.2 represents all routers on the same physical network.

Note

The Internet Assigned Numbers Authority (IANA) is responsible for this list of reserved addresses. For more information on the reserved address assignments, please see the IANA website.

  - **GROUP\_PORT:** This defines the port number through which all communication with the multicast group will take place. Again, the value in this example is arbitrary and you are free to choose your own.

  - **UdpAnySourceMulticastClient:** This class is available in Windows Phone OS 7.1 and encapsulates the logic needed to communicate with a multicast group over UDP. In this example, we create an instance of this class and use it in the Join, Send, and Receive methods. For information about receiving multicast traffic from a single source, see [UdpSingleSourceMulticastClient](https://msdn.microsoft.com/en-us/library/system.net.sockets.udpsinglesourcemulticastclient\(v=VS.105\)).
  1. When the app starts, we want to immediately join the multicast group and start receiving data. In this example, we perform this join action in the OnNavigatedTo method. In the MainPage class, add the following method.

            /// <summary>
            /// Override the OnNavigatedTo method.
            /// </summary>
            protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                // Create a new UdpAnySourceMulticastClient instance and join the group.
                Join();
            }
    
  2. In the MainPage class, add the following method.

            /// <summary>
            /// Create a new UdpAnySourceMulticastClient instance and join the group.
            /// </summary>
            private void Join()
            {
                // Initialize the receive buffer
                _receiveBuffer = new byte[MAX_MESSAGE_SIZE];
    
                // Create the UdpAnySourceMulticastClient instance using the defined 
                // GROUP_ADDRESS and GROUP_PORT constants. UdpAnySourceMulticastClient is a 
                // client receiver for multicast traffic from any source, also known as Any Source Multicast (ASM)
                _client = new UdpAnySourceMulticastClient(IPAddress.Parse(GROUP_ADDRESS), GROUP_PORT);
    
                // Make a request to join the group.
                _client.BeginJoinGroup(
                    result =>
                    {
                        // Complete the join
                        _client.EndJoinGroup(result);
    
                        // The MulticastLoopback property controls whether you receive multicast 
                        // packets that you send to the multicast group. Default value is true, 
                        // meaning that you also receive the packets you send to the multicast group. 
                        // To stop receiving these packets, you can set the property following to false
                         _client.MulticastLoopback = true;
    
                        // Set a flag indicating that we have now joined the multicast group 
                        _joined = true;
    
                        // Let others know we have joined by sending out a message to the group.
                        Send("Joined the group");
    
                        // Wait for data from the group. This is an asynchronous operation 
                        // and will not block the UI thread.
                        Receive();
                    }, null);
            }
    

    This method first creates an instance of the UdpAnySourceMulticastClient class using the group address and port value defined. At this point, we have not yet joined the group. To do that, we call the BeginJoinGroup method on our UdpAnySourceMulticastClient instance. This is an asynchronous call. The callback is implemented inline in the preceding code, but you can move this to its own method if that is the preferred style. In this callback, we complete the join, set a flag to indicate that we have joined the group, and then immediately send a message to the group using the Send method. We also start “listening” for traffic on the group by calling the Receive method. The Send and Receive methods are implemented in MainPage.xaml.cs and are described in the following sections.

Sending data to a multicast group

To send data to a multicast group

  • In the MainPage class, add the following method.

            /// <summary>
            /// Send the given message to the multicast group.
            /// </summary>
            /// <param name="message">The message to send</param>
            private void Send(string  message)
            {
                // Attempt the send only if you have already joined the group.
                if (_joined)
                {
                    byte[] data = Encoding.UTF8.GetBytes(message);
                    _client.BeginSendToGroup(data, 0, data.Length,
                        result =>
                        {
                            _client.EndSendToGroup(result);
    
                            // Log what we just sent
                            Log(message, true);
    
                        }, null);
                }
                else
                {
                    Log("Message was not sent since you are not joined to the group", true);
                }
            }
    

    The preceding method takes a string of text as input and sends it to the multicast group. A check is first made to confirm that we have joined the group. The BeginSendToGroup asynchronous method is used to send the data to the multicast group. The callback for this method is implemented inline. This callback completes the send operation, logs the message that was sent to the app UI, and then continues listening for data from the group. By default, the MulticastLoopback property of the UdpAnySourceMulticastClient is true, which means you will receive the messages you sent to the group. If this property is set to false, you will not receive the messages that you send.

Receiving data from a multicast group

To receive data from a multicast group

  • In the MainPage class, add the following method.

            /// <summary>
            /// Receive data from the group and log it.
            /// </summary>
            private void Receive()
            {
                // Only attempt to receive if you have already joined the group
                if (_joined)
                {
                    Array.Clear(_receiveBuffer, 0, _receiveBuffer.Length);
                    _client.BeginReceiveFromGroup(_receiveBuffer, 0, _receiveBuffer.Length,
                        result =>
                        {
                            IPEndPoint source;
    
                            // Complete the asynchronous operation. The source field will 
                            // contain the IP address of the device that sent the message
                            _client.EndReceiveFromGroup(result, out source);
    
                            // Get the received data from the buffer.
                            string dataReceived = Encoding.UTF8.GetString(_receiveBuffer, 0, _receiveBuffer.Length);
    
                            // Create a log entry.
                            string message = String.Format("[{0}]: {1}", source.Address.ToString(), dataReceived);
    
                            // Log it.
                            Log(message, false);
    
                            // Call receive again to continue to "listen" for the next message from the group
                            Receive();
                        }, null);
                }
                else
                {
                    Log("Cannot receive. You are currently not joined to the group", true);
                }
            }
    

    In the preceding method, data is received from the multicast group using the BeginReceiveFromGroup asynchronous method. The callback for this method is implemented inline. This callback completes the receive operation. Note that in the EndReceiveFromGroup, the source IP address is returned as an out parameter. This specifies the address of the group member that sent this data to the group. One use of this source address would be to communicate directly back to this source using the unicast BeginSendTo asynchronous method. In this example, we simply log the address to the app UI to show who the source of each message is.

Running the UDP multicast app

This section describes how to run the app that was produced in this topic.

To run the UDP multicast app

  1. On a device or emulator, run the app by selecting the Debug | Start Debugging menu command.

  2. When the app starts, you should see text in the messages area notifying you that you have joined the multicast group.

  3. If the app has joined the multicast group successfully, you can now enter text into the input text field labeled Text To Send and click the Send button to send the data to the multicast group.

  4. The messages you send should also appear in the messages area as outgoing messages (indicated by the >> symbol) and incoming messages (indicated by the << symbol).

  5. After the app is working on the emulator, you should test this app using another emulator on another computer or using other devices that are connected over Wi-Fi to the same sub-network.

Other considerations when creating a multicast app

This topic demonstrates how to communicate over a multicast group. The preceding code implements the basic Join Send Receive operations. You should consider the following when creating your multicast app. This list is not exhaustive. It highlights some of the considerations for productizing your app.

Other considerations when creating a multicast app

  • Error Handling: Each call to the asynchronous methods on UdpAnySourceMulticastClient has the potential to throw an exception. A SocketException exception occurs when there is an error accessing the socket. You should handle these exceptions appropriately.

  • Fast Application Switching: When your app is reactivated, you rejoin the multicast group by calling BeginJoinGroup again. You can use the same UdpAnySourceMulticastClient object.

  • Communicate using Unicast: This example demonstrates how to communicate in a multicast group by sending and receiving multicast messages. This is the recommended way to implement peer-to-peer communication. As stated in the preceding sections, the source endPoint for each message received can be used to communicate directly with the given source. An example of this is functionality is available for download. For more information, see Multicast Sockets Sample.

See Also

Reference

System.Net.Sockets

Microsoft.Phone.Net.NetworkInformation

Other Resources

Sockets for Windows Phone 8

How to create and use a TCP socket client app for Windows Phone 8

How to create and use a UDP socket client app for Windows Phone 8

Multicast Sockets Sample

Network and network interface information for Windows Phone 8