2014-02-24 65 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