UPnP多播:M-SEARCH(发现)缺少响应

15

我创建了一个小程序来测试UPnP组播(使用Visual C# 2010 Express,在Windows 7 Professional 64位上运行)。我可以接收来自网络中的UPnP设备的UPnP NOTIFY消息。但是当我发送M-SEARCH消息时,却没有得到回应。

我已经在iOS环境下进行了相同代码的测试(使用Monotouch for iOS,在Mac上运行的iPhone模拟器)。在那里,它运行良好,并且我能够获得来自我的UPnP设备的所有搜索响应。我也可以从我的Windows程序中看到M-SEARCH消息。

看起来Windows(或防火墙?)正在隐藏搜索响应。有任何想法吗?

这是代码:

IPEndPoint LocalEndPoint = new IPEndPoint(IPAddress.Any, 1900);
IPEndPoint MulticastEndPoint = new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900);

Socket UdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

UdpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
UdpSocket.Bind(LocalEndPoint);
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(MulticastEndPoint.Address, IPAddress.Any));
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 2);
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, true);

Console.WriteLine("UDP-Socket setup done...\r\n");

string SearchString = "M-SEARCH * HTTP/1.1\r\nHOST:239.255.255.250:1900\r\nMAN:\"ssdp:discover\"\r\nST:ssdp:all\r\nMX:3\r\n\r\n";

UdpSocket.SendTo(Encoding.UTF8.GetBytes(SearchString), SocketFlags.None, MulticastEndPoint);

Console.WriteLine("M-Search sent...\r\n");

byte[] ReceiveBuffer = new byte[64000];

int ReceivedBytes = 0;

while (true)
{
    if (UdpSocket.Available > 0)
    {
        ReceivedBytes = UdpSocket.Receive(ReceiveBuffer, SocketFlags.None);

        if (ReceivedBytes > 0)
        {
            Console.WriteLine(Encoding.UTF8.GetString(ReceiveBuffer, 0, ReceivedBytes));
        }
    }
}

多播端点设置为什么? - simonc
你确定在iOS上看到的M-SEARCH是来自你的Windows程序吗?你尝试过在Windows上使用另一个UPnP发现工具吗? - Pavel Zdenek
@PavelZdenek:是的,我确定。我在M-SEARCH消息上附加了一些额外的字符,以便我可以在iOS上识别该消息。 - Jörn
3个回答

19

是的,我解决了这个问题!一个小错误造成了巨大的影响:

我的程序在端口1900上向UPnP多播组发送M-SEARCH请求。因为我将LocalEndPoint绑定到了同一端口,UPnP设备通过单播回复到了端口1900。在iOS上,它可以工作,因为我的程序是唯一绑定到该端口的服务。但是在PC上,我发现有几个服务绑定到了端口1900 (使用"netstat -p UDP -a"命令查找)。因此,UPnP设备的单播消息被其中一个其他服务吸收了。

解决方案:我将LocalEndPoint绑定到空闲端口(例如60000),现在一切正常了!

IPEndPoint LocalEndPoint = new IPEndPoint(IPAddress.Any, 60000);

1
你比我快了 :-) 是的,Windows 默认运行 SSDP 服务。使用 netstat 选项 -b 查看一下。 - Pavel Zdenek
我有相同的问题,但我无法更改我的端口。是否有其他方法来解决这个问题? - Kingpin
5
不要绑定到特定的端口(60000),而是请求一个临时端口(0)!否则,有一天会因为其他人使用了60000而导致失败。 - Nas Banov

5
创建本地端点时,请使用端口0(零)来绑定一个不使用固定端口的空闲端口。另外一个发现是,绑定 IPAddress.Any 或 IPAddress.Loopback 将从 Microsoft(本地?)系统获得响应,而绑定到 LAN 地址之一将从本地网络获得响应。获取第一个 IPV4 地址可以通过以下方式完成:
IPAddress localNetwork = Dns.GetHostAddresses(Environment.GetEnvironmentVariable("COMPUTERNAME")).Where(ia => (ia.AddressFamily == AddressFamily.InterNetwork)).First();

IPv4 没有真正的边界,我发现了 IP V6 的多播地址 FF02::C(链路本地)、FF05::C(站点本地)、FF08::C(组织本地)和 FF0E::C(全局)。请注意,IP V4 的范围是站点本地。来源:Wikipedia - SSDP - VBWebProfi
Environment.GetEnvironmentVariable("COMPUTERNAME") 可以被替换为 Environment.MachineName - VBWebProfi
谢谢这个。IPAddress.Any 对于我的机器返回了 0.0.0.0,导致没有发送/接收任何内容(我配置了大约30个 VPN 和其他网络适配器,可能是原因)。 - apc

1

为了后人:对于M-SEARCH,设置所有这些选项都是不必要的,甚至可能产生反作用。

UdpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(MulticastEndPoint.Address, IPAddress.Any));
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 2);
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, true);

所以不要这样做。

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