Windows Phone 8上的UDP多播组

时间:2012-11-23 11:34:15

标签: c# sockets udp windows-phone-8 datagram

好的,这是我几天试图弄清楚的。我们在Windows Phone 7上有一个应用程序,其中电话加入多播组,然后向该组发送和接收消息以相互通信。注意 - 这是电话与电话的通信。

现在我正在尝试将此应用程序移植到Windows Phone 8 - 使用Visual Studio 2012中的“转换为电话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企业版

我无法告诉你很多关于无线网络的工作 - 除了Phone 7设备没有问题。

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

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

任何输入都会受到赞赏,因为这让我很生气。

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

你有没有试过加入另一个组播组?因为在IANA分配中似乎正在使用224.0.1.1。你找到了所有的here

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

答案 2 :(得分:1)

根据我的经验,UDP多播在windows phone 7下的工作非常奇怪,所以你应该在Windows Phone 8上查看相同内容。

以下是我的经历:

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