2014-02-24 68 views
5

我试图做一个Web服务发现使用WCF的DiscoveryClient使用此代码:WCF的Web服务发现解决

// 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 Device Manager,似乎有同样的问题。

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

+0

[本页](http://msdn.microsoft.com/en-us/library/bb706924.aspx#LinkTarget_1973)提到设置'/秒:信封/秒:页眉/一个:ReplyTo'地址,但我不确定这可以在WCF中设置。 – Deanna

+0

你有没有解决过这个问题?我遇到同样的问题 – HypeZ

+0

@HypeZ Nope,这仍然是一个问题。 – Deanna

回答

2

那么,我有同样的问题,经过几天的研究,阅读ONVIF文件和学习关于多播的一些技巧,我开发了这个代码工作正常。 作为一个例子,我的网络适配器上的主要IP地址是192.168.80.55,并且我还在高级设置中设置了另一个IP(192.168.0.10)。通过使用此代码,我可以发现IP地址为192.168.0.12的摄像机的设备服务。 本示例最重要的部分是“DeepDiscovery”方法,其中包含了对网络地址进行迭代以及组播正确的Probe消息的主要思想。 我建议在“GetSocketResponse”方法中对响应进行反序列化。目前,只需使用Regex提取服务URI即可。

正如这篇文章(https://msdn.microsoft.com/en-us/library/dd456791(v=vs.110).aspx)中提到:

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

我做的是WS-发现不准确的动作,并使用标准的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); 
      //... 
     } 
    } 
} 
+0

这看起来很合理,但我不再有能力去测试它了,谢谢你的回应。 – Deanna