此页面有用吗?
您对此内容的反馈非常重要。 请告诉我们您的想法。
更多反馈?
1500 个剩余字符
MSDN Library
信息
您所需的主题如下所示。但此主题未包含在此库中。

如何通过多播组为 Windows Phone 8 发送和接收数据

2014/6/18

适用于:Windows Phone 8 和 Windows Phone Silverlight 8.1 | Windows Phone OS 7.1

 

本主题演示如何通过多播组进行通信。多播流量是一种适用于 Internet 上的多对多通信的可伸缩方式。通信在多播组内发生,每个多播组都由 IP 地址(称为多播组地址)标识。设备订阅多播组地址。然后,已订阅设备发送到多播组的所有数据包都由订阅该多播地址的所有其他设备接收。本主题介绍在 Windows Phone OS 7.1 中使用 System.Net.Sockets 命名空间中提供的 UdpAnySourceMulticastClient 类加入多播组所需的步骤。演示该功能的应用的完整示例可供下载。有关更多信息,请参见多播套接字示例

本主题包括以下部分。

 

在本节中,将创建用于演示 UDP 多播功能的 UI。这是一个 Windows Phone 应用。应用启动时,即会加入多播组。应用加入多播组之后,可以接收发送到多播组的消息,还可以向多播组发送消息。UI 将显示发送到多播组的所有数据。您还可以键入消息并将其发送到多播组。

创建 UI

  1. 在 Visual Studio 中,通过选择“文件” | “新建项目”菜单命令创建新的项目。

  2. 将显示“新建项目”窗口。展开“Visual C#”模板,然后选择“Windows Phone”模板。

  3. 选择 Windows Phone 应用  模板。用您选择的名称填写“名称”

  4. 单击“确定”。将显示 Windows Phone 平台选择对话框。选择面向的版本或接受默认版本。

  5. 单击“确定”。将创建一个新的项目,并且“MainPage.xaml”将在 Visual Studio 设计器窗口中打开。

  6. “MainPage.xaml”中,删除名为“LayoutRoot”的 Grid 的 XAML 代码,然后使用以下代码进行替换:

    
         <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>
    
    
    

    前面的 XAML 代码会创建一个类似于以下屏幕快照的简单用户界面。

    BasicUDPMulticastClient How To Screenshot

    事件处理程序 btnSend_Click 将在以下各节中介绍。

  7. 为了将数据发送到多播组,应用使用一个 TextBox(用于接受来自用户的文本)和一个按键(点按该按键时,会将 TextBox 中的文本发送到多播组)。由于将激发 btnSend_Click 事件,我们向代码隐藏文件添加一个事件处理程序来处理该事件。在“解决方案资源管理器”中,右键单击 MainPage.xaml,然后单击“查看代码”。代码隐藏文件将在代码编辑器中打开。在页面代码隐藏文件的顶部,添加以下方法:

    
            /// <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);
                }
            }
    
    
    

    该方法首先确保输入文本框包含一些文本,然后通过调用 Send,传入要发送的文本将数据发送到多播组。Send 方法将在以下各节中介绍。

  8. 为了显示在多播组中收发的消息,用户界面中包含一个称为 lbLogListBox。以下代码用于将收到的消息添加到 ListBox 中。在“解决方案资源管理器”中,右键单击 MainPage.xaml,然后单击“查看代码”。代码隐藏文件将在代码编辑器中打开。在页面代码隐藏文件的顶部,添加以下方法。

    
            /// <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);
                });
                
            }
    
    

    前面的方法接受一个消息字符串和一个表明所记录消息是传入此设备的消息还是传出消息(即此设备发送的消息)的指示。修改此消息以包含方向指示符和时间戳。此消息随后会添加到列表框并滚动到视图中,以便用户总是可以看到所记录的最后一条消息。所有这些 UI 操作都包装在 BeginInvoke 中,以保证始终可以对 UI 线程执行它们。这是一个安全防范措施,因为此示例包含一些异步操作,它们将在 UI 线程以外的其他线程上运行。

在本节中,您将加入多播组,以便可以在该组中发送和接收数据。

加入多播组

  1. “解决方案资源管理器”中,右键单击 MainPage.xaml,然后单击“查看代码”。代码隐藏文件将在代码编辑器中打开。在页面代码隐藏文件的顶部,添加以下语句:

    
    using System.Net.Sockets;
    using System.Text;
    
  2. MainPage 类的顶部,定义以下成员。

    
            // 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;
    
    

    对于前面的代码,应该注意以下几点:

    • GROUP_ADDRESS:多播组由多播组地址定义,该地址是必须介于 224.0.0.0239.255.255.255 之间的 IP 地址。范围介于 224.0.0.0224.0.0.255(包含 224.0.0.0 和 224.0.0.255)之间的多播地址是“较为熟知”的保留多播地址。例如,224.0.0.0 是基址,224.0.0.1 是代表同一个物理网络中所有系统的多播组地址,而 224.0.0.2 代表同一个物理网络中的所有路由器。

      说明注意:

      Internet 编号分配管理机构 (IANA) 负责此保留的地址列表。有关保留的地址分配的更多信息,请参见 IANA 网站

    • GROUP_PORT:此代码定义与多播组发生所有通信所使用的端口号。还有,此示例中的值是随机的,您可以随意选择自己的值。

    • UdpAnySourceMulticastClient:此类在 Windows Phone OS 7.1 中可用,并且封装了通过 UDP 与多播组通信所需的逻辑。在此示例中,我们将创建此类的一个实例,并将其用在 JoinSendReceive 方法中。有关从单一源接收多播流量的信息,请参见 UdpSingleSourceMulticastClient

  3. 应用启动时,我们希望立即加入多播组并开始接收数据。在此示例中,我们在 OnNavigatedTo 方法中执行此加入操作。在 MainPage 类中,添加以下方法。

    
            /// <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();
            }
    
    
  4. MainPage 类中,添加以下方法。

    
            /// <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);
            }
    
    

    此方法首先使用定义的组地址和端口值创建 UdpAnySourceMulticastClient 类的一个实例。此时,我们尚未加入该组。为此,我们调用 UdpAnySourceMulticastClient 实例上的 BeginJoinGroup 方法。这是异步调用。回调是在前面的代码中内联实现的,但您可以将其移动到其自身的方法中(如果这是首选样式)。在此回调中,我们将完成加入,设置一个标志来指示我们已加入组,然后使用 Send 方法立即将消息发送到该组。我们还通过调用 Receive 方法开始“侦听”组中的流量。SendReceive 方法是在 MainPage.xaml.cs 中实现的,以下各节描述了这些方法。

将数据发送到多播组

  • MainPage 类中,添加以下方法。

    
            /// <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);
                }
            }
    
    

    前面的方法将一串文本用作输入,并将其发送到多播组。首先进行检查以确认我们已加入组中。使用 BeginSendToGroup 异步方法将数据发送到多播组。对此方法的回调是内联实现的。此回调将完成发送操作,记录发送到应用 UI 的消息,然后继续侦听来自该组的数据。默认情况下,UdpAnySourceMulticastClientMulticastLoopback 属性为 true,表示您会收到自己发送到该组的消息。如果此属性设置为 false,则将无法接收自己发送的消息。

从多播组接收数据

  • MainPage 类中,添加以下方法。

    
            /// <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);
                }
            }
    
    

    在前面的方法中,系统使用 BeginReceiveFromGroup 异步方法从多播组接收数据。对此方法的回调是内联实现的。此回调会完成接收操作。请注意,在 EndReceiveFromGroup 中,源 IP 地址是作为 out 参数返回的。这指定了将此数据发送到组的组成员的地址。此源地址的一个用途是使用单播 BeginSendTo 异步方法直接与此源进行回归通信。在此示例中,我们只记录应用 UI 的地址以显示每条消息的来源。

本节介绍如何运行本主题中生成的应用。

运行 UDP 多播应用

  1. 在设备或模拟器上,通过选择“调试 | 启动调试”菜单命令来运行应用。

  2. 当应用启动时,应该会在消息区域中看到文本,通知您已加入多播组。

  3. 如果应用已成功加入多播组,现在可以在标记为“要发送的文本”的输入文本字段中输入文本,然后点按“发送”按键将数据发送到多播组。

  4. 您发送的消息还应该作为传出消息(由 >> 符号指示)和传入消息(由 << 符号指示)显示在消息区域中。

  5. 当应用在模拟器上运行之后,您应该在其他计算机上使用另一个模拟器测试此应用,或使用通过 WLAN 连接到同一个子网络的其他设备进行测试。

本主题演示如何通过多播组进行通信。前面的代码实现了基本的加入、发送和接收操作。在创建多播应用时应考虑以下几点。此列表仅列出了部分注意事项。其中突出显示了创建应用时应考虑一些注意事项。

创建多播应用时的其他注意事项

  • 错误处理:对 UdpAnySourceMulticastClient 中异步方法的每个调用都有可能会引发异常。当访问套接字出错时会发生 SocketException 异常。 您应该适当地处理这些异常。

  • 快速应用程序切换:当重新激活应用时,可以通过再次调用 BeginJoinGroup 重新加入多播组。可以使用同一个 UdpAnySourceMulticastClient 对象。

  • 使用单播进行通信:此示例演示如何通过发送和接收多播消息在多播组中进行通信。建议使用这种方式来实现对等通信。如前面的各节所述,可以使用每条收到的消息的源终结点直接与给定源通信。此功能的示例可供下载。有关更多信息,请参见多播套接字示例

显示:
© 2015 Microsoft