Windows Phone 8 上的 UDP 多播组

Posted

技术标签:

【中文标题】Windows Phone 8 上的 UDP 多播组【英文标题】:UDP multicast group on Windows Phone 8 【发布时间】:2012-11-11 18:29:04 【问题描述】:

好的,这是我几天来一直在尝试解决的问题。我们在 Windows Phone 7 上有一个应用程序,其中电话加入一个多播组,然后向该组发送和接收消息以相互交谈。注意 - 这是电话到电话的通信。

现在我正在尝试将此应用程序移植到 Windows Phone 8 - 使用 Visual Studio 2012 中的“转换为 Phone 8”功能 - 到目前为止一切顺利。直到我尝试测试电话到电话的通信。手机似乎很好地加入了该组,并且它们可以发送数据报。他们甚至会收到他们发送给群组的消息 - 但是,没有手机会收到来自其他手机的消息。

这是我页面后面的示例代码:

// Constructor
public MainPage()

    InitializeComponent();


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

// A client receiver for multicast traffic from any source
UdpAnySourceMulticastClient _client = null;

// Buffer for incoming data
private byte[] _receiveBuffer;

// Maximum size of a message in this communication
private const int MAX_MESSAGE_SIZE = 512;

private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)

    _client = new UdpAnySourceMulticastClient(IPAddress.Parse(GROUP_ADDRESS), GROUP_PORT);
    _receiveBuffer = new byte[MAX_MESSAGE_SIZE];

    _client.BeginJoinGroup(
        result =>
        
            _client.EndJoinGroup(result);
            _client.MulticastLoopback = true;
            Receive();
        , null);


private void SendRequest(string s)

    if (string.IsNullOrWhiteSpace(s)) return;

    byte[] requestData = Encoding.UTF8.GetBytes(s);

    _client.BeginSendToGroup(requestData, 0, requestData.Length,
        result =>
        
            _client.EndSendToGroup(result);
            Receive();
        , null);


private void Receive()

    Array.Clear(_receiveBuffer, 0, _receiveBuffer.Length);
    _client.BeginReceiveFromGroup(_receiveBuffer, 0, _receiveBuffer.Length,
        result =>
        
            IPEndPoint source;

            _client.EndReceiveFromGroup(result, out source);

            string dataReceived = Encoding.UTF8.GetString(_receiveBuffer, 0, _receiveBuffer.Length);

            string message = String.Format("[0]: 1", source.Address.ToString(), dataReceived);
            Log(message, false);

            Receive();
        , null);


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



private void btnSend_Click(object sender, RoutedEventArgs e)

    // Don't send empty messages.
    if (!String.IsNullOrWhiteSpace(txtInput.Text))
    
        //Send(txtInput.Text);
        SendRequest(txtInput.Text);
    


private void btnStart_Click(object sender, RoutedEventArgs e)

    SendRequest("start now");

为了简单地测试 UDP 堆栈,我从 MSDN 下载了示例here,并在一对 Windows Phone 7 设备上进行了测试,它按预期工作。然后我转换到 Windows Phone 8 并部署到我的手机上,设备似乎再次启动了它们的连接,用户可以输入他们的名字。但是,这些设备再次无法看到其他设备或与其他设备通信。

最后我使用新的 DatagramSocket 实现了一个简单的通信测试,我再次看到成功启动,但没有设备间通信。

这是使用数据报套接字实现的相同页面背后的代码:

// Constructor
public MainPage()

    InitializeComponent();


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

private DatagramSocket socket = null;

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


private void btnSend_Click(object sender, RoutedEventArgs e)

    // Don't send empty messages.
    if (!String.IsNullOrWhiteSpace(txtInput.Text))
    
        //Send(txtInput.Text);
        SendSocketRequest(txtInput.Text);
    


private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)

    socket = new DatagramSocket();
    socket.MessageReceived += socket_MessageReceived;

    try
    
        // Connect to the server (in our case the listener we created in previous step).
        await socket.BindServiceNameAsync(GROUP_PORT.ToString());
        socket.JoinMulticastGroup(new Windows.Networking.HostName(GROUP_ADDRESS));
        System.Diagnostics.Debug.WriteLine(socket.ToString());
    
    catch (Exception exception)
    
        throw;
    


private async void SendSocketRequest(string message)

    // Create a DataWriter if we did not create one yet. Otherwise use one that is already cached.
    //DataWriter writer;
    var stream = await socket.GetOutputStreamAsync(new Windows.Networking.HostName(GROUP_ADDRESS), GROUP_PORT.ToString());
    //writer = new DataWriter(socket.OutputStream);
    DataWriter writer = new DataWriter(stream);

    // Write first the length of the string as UINT32 value followed up by the string. Writing data to the writer will just store data in memory.
   // stream.WriteAsync(
    writer.WriteString(message);

    // Write the locally buffered data to the network.
    try
    
        await writer.StoreAsync();
        Log(message, true);
        System.Diagnostics.Debug.WriteLine(socket.ToString());
    
    catch (Exception exception)
    
        throw;
    
    finally
    
        writer.Dispose();
    


void socket_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)

    try
    
        uint stringLength = args.GetDataReader().UnconsumedBufferLength;
        string msg = args.GetDataReader().ReadString(stringLength);

        Log(msg, false);
    
    catch (Exception exception)
    
        throw;
    

昨晚我把手机带回家在我家的无线网络上进行测试,结果我发现我的设备通信成功了。

回顾一下 - 我的旧版 Windows Phone 7 代码在我的工作网络上运行良好。 Windows Phone 8 的端口(没有实际代码更改)不发送设备间通信。此代码确实适用于我的家庭网络。代码在附加调试器的情况下运行,并且在执行期间任何地方都没有错误或异常的迹象。

我使用的手机是:

Windows Phone 7 - 诺基亚 Lumia 900 (* 2)、诺基亚 Lumia 800 (* 3) Windows Phone 8 - 诺基亚 Lumia 920 (* 1)、诺基亚 Limia 820 (* 2)

这些都运行最新的操作系统,并处于开发者模式。 开发环境是运行 Visual Studio 2012 Professional 的 Windows 8 Enterprise

我不能告诉你很多关于工作无线网络的信息——除了 Phone 7 设备没有任何问题。

至于我使用的家庭无线网络,那只是一个基本的 BT 宽带路由器,没有改变任何“开箱即用”设置。

显然这两个网络的配置方式存在问题,但 Windows Phone 8 实现 UDP 消息的方式也很明显存在问题。

任何意见都将不胜感激,因为这让我现在很生气。

【问题讨论】:

我从 Microsoft 得到的最新评论是,这可能与堆栈中的错误有关。截至目前,我正在等待他们的回音。当我听到更多消息时,我会更新这篇文章。但是,如果将 SendSocketRequest 实现的第一行更改为:var stream = await socket.GetOutputStreamAsync(new Windows.Networking.HostName(IPAddress.Broadcast.ToString()), GROUP_PORT.ToString());,则可以使 WinRT 实现工作 尝试使用不同的组地址,如“239.0.0.11”。 还有来自微软的消息吗?我遇到了同样的问题,但没有找到解决方法。 我也有同样的问题。有什么新消息吗?? @nucleons 我没有从微软那里听到任何其他消息,因为他们确认该错误在他们的堆栈中。我们正在使用我上面描述的解决方法;既然它有效,我们就开始着手我们的新工作项目。如果我从 MS 那里听到任何关于此问题的解决方案,我会及时更新这篇文章。 【参考方案1】:

我注意到您使用了环回。我认为这意味着当您从客户发送消息时,您也会收到您发送的消息。这意味着您的接收处理程序将触发。它具有以看似非线程安全的方式清除接收缓冲区的效果。尝试在您的接收方法中添加一些 try catch 并查看是否发生了任何不良情况,但您可能在任何情况下都不使用共享接收缓冲区。

【讨论】:

【参考方案2】:

您是否尝试过加入另一个多播组?因为 224.0.1.1 似乎在 IANA 分配中使用。你会找到所有的here。

也许在 Windows Phone 8 上,某些服务会更紧密地监听传入的消息(例如,在内核模式下运行的网络服务)并且它们永远不会转发给您。

【讨论】:

【参考方案3】:

根据我的经验,UDP 多播在 windows phone 7 下的工作非常奇怪,所以你应该为 windows phone 8 签出相同的结果。

这是我的经验:

    查看官方支持的内容,例如在 Windows Phone OS 7.1(我在切换之前尝试的最后一个操作系统)下,支持 TCP 单播、UDP 单播和 UDP 多播客户端。 某些版本的 Windows phone 仅在客户端首次打开它并且在不超过 10 秒内收到会话时才允许接收 UDP 会话,这似乎是 Windows Phone 上的某种安全措施。 尝试使用不同的地址:224.0.0.0 到 224.0.0.255(含)范围内的多播地址是“众所周知的”保留多播地址。 在虚拟机和真实手机设备中检查,行为可能会有所不同。

【讨论】:

以上是关于Windows Phone 8 上的 UDP 多播组的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中跨本地网络进行 UDP 多播?

Windows Phone 8.1 上的 RadioButtons 绑定

UDP 单播广播多播

Windows Phone 8 上的 Azure 表存储使用啥库?

Windows Phone 8上的文本换行列表框

Windows Phone 8.1 上的 WiFi 直连