Windows Store 应用程序(.NET)上的 SSDP(UDP)

3
我正在尝试使用C#实现一个基本的SSDP(UDP)广播/监听器,用于Windows Store应用程序。
我发现Windows.Networking.Sockets包含DatagramSocket类,这是我需要用于UDP网络的类。
然而,我的当前尝试似乎执行得很好,但在Wireshark中没有结果,并且未从网络上的设备获得响应。
以下是我目前正在使用的代码(并通过RT模拟器运行):
public async static Task<IEnumerable<HueBridge>> DiscoverAsync(TimeSpan timeout)
{
  if (timeout <= TimeSpan.Zero)
    throw new ArgumentException("Timeout value must be greater than zero.", "timeout");

  var discoveredBridges = new List<HueBridge>();

  using (var socket = new DatagramSocket())
  {
    while (true)
    {
      var bridgeWasFound = false;

      socket.MessageReceived += (sender, e) =>
      {
        var bpx = true; // breakpoint here for success
      };

      var multicastIP = new HostName("239.255.255.250");
      await socket.BindServiceNameAsync("1900");
      socket.JoinMulticastGroup(multicastIP);

      using (var writer = new DataWriter(socket.OutputStream))
      {
        var request = new StringBuilder();
        request.AppendLine("M-SEARCH * HTTP/1.1");
        request.AppendLine("HOST: 239.255.255.250:1900");
        request.AppendLine("MAN: ssdp:discover");
        request.AppendLine("MX: 5");
        request.AppendLine("ST: ssdp:all");

        writer.WriteString(request.ToString());
        await writer.FlushAsync();
      }

      if (timeout > TimeSpan.Zero)
        await Task.Delay(timeout);

      if (!bridgeWasFound)
        break; // breakpoint here for failure check
    }
  }

  return discoveredBridges;
}

我可能做错了什么?我没有收到异常,并且在清单文件中设置了正确的能力。我的break断点总是被触发,而且我使用了10秒的超时时间。

2个回答

3

看来我已经找到了问题。

首先,我应该使用 socket.BindEndpointAsync(null, string.Empty) 而不是 socket.BindServiceNameAsync("1900"),这样可以正确监听广播数据包。

其次,writer.FlushAsync() 不会写入套接字; 但是,writer.StoreAsync() 可以。

以下是最终结果,几乎完美运行:

public async static Task<IEnumerable<HueBridge>> DiscoverAsync(TimeSpan timeout)
{
  if (timeout <= TimeSpan.Zero)
    throw new ArgumentException("Timeout value must be greater than zero.", "timeout");

  var discoveredBridges = new List<HueBridge>();
  var multicastIP = new HostName("239.255.255.250");
  var bridgeWasFound = false;

  using (var socket = new DatagramSocket())
  {
    socket.MessageReceived += (sender, e) =>
    {
      var reader = e.GetDataReader();
      var bytesRemaining = reader.UnconsumedBufferLength;
      var receivedString = reader.ReadString(bytesRemaining);

      // TODO: Check for existing bridges, only add new ones to prevent infinite loop.
      // TODO: Create new bridge and add to the list. 

      bridgeWasFound = true;
    };

    await socket.BindEndpointAsync(null, string.Empty);
    socket.JoinMulticastGroup(multicastIP);

    while (true)
    {
      bridgeWasFound = false;

      using (var stream = await socket.GetOutputStreamAsync(multicastIP, "1900"))
      using (var writer = new DataWriter(stream))
      {
        var request = new StringBuilder();
        request.AppendLine("M-SEARCH * HTTP/1.1");
        request.AppendLine("HOST: 239.255.255.250:1900");
        request.AppendLine("MAN: ssdp:discover");
        request.AppendLine("MX: 3");
        request.AppendLine("ST: ssdp:all");

        writer.WriteString(request.ToString());
        await writer.StoreAsync();

        if (timeout > TimeSpan.Zero)
          await Task.Delay(timeout);

        if (!bridgeWasFound)
          break;
      }
    }
  }

  return discoveredBridges;
}

1

根据规范:

HTTP扩展框架需要MAN字段。与NTS和ST字段值不同,MAN头字段的字段值用双引号括起来;它定义了扩展的范围(命名空间)。必须是"ssdp:discover"。

然后您的代码

request.AppendLine("MAN: ssdp:discover");

必须是。
request.AppendLine("MAN: \"ssdp:discover\"");

希望这有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接