繁体   English   中英

具有多个 IP 地址的网络接口上的 WCF Web 服务发现

[英]WCF web service discovery on network interfaces with multiple IP addresses

我正在尝试使用以下代码使用 WCF 的DiscoveryClient进行网络服务DiscoveryClient

// Setup the discovery client (WSDiscovery April 2005)
DiscoveryEndpoint discoveryEndpoint = new UdpDiscoveryEndpoint(DiscoveryVersion.WSDiscoveryApril2005);
DiscoveryClient discoveryClient = new DiscoveryClient(discoveryEndpoint);

// Setup the wanted device criteria
FindCriteria criteria = new FindCriteria();
criteria.ScopeMatchBy = new Uri("http://schemas.xmlsoap.org/ws/2005/04/discovery/rfc3986");
criteria.Scopes.Add(new Uri("onvif://www.onvif.org/"));

// Go find!
criteria.Duration = TimeSpan.FromMilliseconds(duration);
discoveryClient.FindAsync(criteria, this);

这在具有分配给单个网络接口的单个​​ IP 地址 (10.1.4.25) 的机器上非常有效。 广播从 10.1.4.25 发送到 239.255.255.250,我收到来自同一子网上的 5 个设备的响应。

但是,当机器在同一接口上有多个 IP 时,它似乎会选择一个源 IP 并从中发送请求。 在这种情况下,我从一个提供 169.254 地址的设备收到回复。

我尝试将UdpDiscoveryEndpoint.TransportSettings.MulticastInterfaceId设置为合适的接口 ID,但它没有帮助,因为它标识了单个接口,而不是特定的 IP。 UdpDiscoveryEndpoint.ListenUri属性还返回多播地址,因此不会影响源 IP。 UdpDiscoveryEndpoint.Address是发现协议的 URN。

有什么方法可以强制它从特定的 IP 地址发送,或者理想情况下,每个配置的 IP 上的多个请求?

我也试过ONVIF 设备管理器似乎有同样的问题。

请注意,这与将服务绑定到特定或“所有地址”IP 无关。 它是关于发送发现请求的 IP。

好吧,我遇到了同样的问题,经过几天的研究,阅读 ONVIF 文档并学习了一些有关多播的技巧,我开发了这段代码,效果很好。 例如,我的网络适配器上的主 IP 地址是 192.168.80.55,我还在高级设置中设置了另一个 IP(192.168.0.10)。 通过使用此代码,我可以发现 IP 地址为 192.168.0.12 的摄像机的设备服务。 此示例中最重要的部分是“DeepDiscovery”方法,它包含网络地址迭代和多播正确探测消息的主要思想。 我建议在“GetSocketResponse”方法中反序列化响应。 目前,我只是使用 Regex 提取服务 URI。

如本文所述( https://msdn.microsoft.com/en-us/library/dd456791(v=vs.110).aspx ):

为了让 WCF 发现正常工作,所有 NIC(网络接口控制器)应该只有 1 个 IP 地址。

我正在执行 WS-Discovery 所做的确切操作并使用标准 3702 端口,但我自己构建了 SOAP 信封并使用 Socket 类为已为网络接口控制器设置的所有 IP 地址发送数据包。

class Program
{
    static readonly List<string> addressList = new List<string>();
    static readonly IPAddress multicastAddress = IPAddress.Parse("239.255.255.250");
    const int multicastPort = 3702;
    const int unicastPort = 0;

    static void Main(string[] args)
    {
        DeepDiscovery();
        Console.ReadKey();
    }

    public static void DeepDiscovery()
    {
        string probeMessageTemplate = @"<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope"" xmlns:a=""http://schemas.xmlsoap.org/ws/2004/08/addressing""><s:Header><a:Action s:mustUnderstand=""1"">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</a:Action><a:MessageID>urn:uuid:{messageId}</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><a:To s:mustUnderstand=""1"">urn:schemas-xmlsoap-org:ws:2005:04:discovery</a:To></s:Header><s:Body><Probe xmlns=""http://schemas.xmlsoap.org/ws/2005/04/discovery""><d:Types xmlns:d=""http://schemas.xmlsoap.org/ws/2005/04/discovery"" xmlns:dp0=""http://www.onvif.org/ver10/device/wsdl"">dp0:Device</d:Types></Probe></s:Body></s:Envelope>";

        foreach (IPAddress localIp in
            Dns.GetHostAddresses(Dns.GetHostName()).Where(i => i.AddressFamily == AddressFamily.InterNetwork))
        {
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            socket.Bind(new IPEndPoint(localIp, unicastPort));
            socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(multicastAddress, localIp));
            socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 255);
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            socket.MulticastLoopback = true;
            var thread = new Thread(() => GetSocketResponse(socket));
            var probeMessage = probeMessageTemplate.Replace("{messageId}", Guid.NewGuid().ToString());
            var message = Encoding.UTF8.GetBytes(probeMessage);
            socket.SendTo(message, 0, message.Length, SocketFlags.None, new IPEndPoint(multicastAddress, multicastPort));
            thread.Start();
        }
    }


    public static void GetSocketResponse(Socket socket)
    {
        try
        {
            while (true)
            {
                var response = new byte[3000];
                EndPoint ep = socket.LocalEndPoint;
                socket.ReceiveFrom(response, ref ep);
                var str = Encoding.UTF8.GetString(response);
                var matches = Regex.Matches(str, @"http://\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/onvif/device_service");
                foreach (var match in matches)
                {
                    var value = match.ToString();
                    if (!addressList.Contains(value))
                    {
                        Console.WriteLine(value);
                        addressList.Add(value);
                    }
                }
                //...
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
            //...
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM