2014-02-24 8 views
5

Ich versuche, eine Webservice Entdeckung mit WCF DiscoveryClient mit diesem Code zu tun:WCF Web-Service-Discovery auf Netzwerk-Schnittstellen mit mehreren IP-Adressen

// 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); 

Diese mit einer einzigen IP-Adresse auf einer Maschine funktioniert sehr gut (10.1.4.25) der einzelnen Netzwerkschnittstelle zugewiesen. Die Übertragung wird von 10.1.4.25 an 239.255.255.250 gesendet, und ich bekomme Antworten von 5 Geräten alle im selben Subnetz.

Wenn jedoch der Computer über mehrere IPs auf derselben Schnittstelle verfügt, scheint er eine einzelne Quell-IP auszuwählen und sendet die Anforderung von diesem. In diesem Fall erhalte ich eine Antwort von einem einzelnen Gerät mit einer 169.254-Adresse.

Ich habe versucht, UdpDiscoveryEndpoint.TransportSettings.MulticastInterfaceId auf eine geeignete Schnittstelle ID, die nicht geholfen hat, da es eine einzelne Schnittstelle, nicht eine bestimmte IP identifiziert. Die UdpDiscoveryEndpoint.ListenUri-Eigenschaft gibt auch die Multicast-Adresse zurück und wirkt sich daher nicht auf die Quell-IP aus. UdpDiscoveryEndpoint.Address ist die URN für das Erkennungsprotokoll.

Gibt es eine Möglichkeit, ich kann es zwingen, von einer bestimmten IP-Adresse oder idealerweise mehrere Anfragen auf jedem konfigurierten IP senden?

Ich habe auch versucht ONVIF Device Manager, scheint das gleiche Problem zu haben.

Beachten Sie, dass es hier nicht darum geht, dass ein Dienst an eine bestimmte IP-Adresse gebunden wird. Es handelt sich um die IP-Adresse, von der eine Suchanforderung gesendet wird.

+0

[Diese Seite] (http://msdn.microsoft.com/en-us/library/bb706924.aspx#LinkTarget_1973) erwähnt die '/ s Einstellung: Envelope/s: Header/a: ReplyTo' Adressen, aber ich bin mir nicht sicher, dass dies in WCF eingestellt werden kann. – Deanna

+0

hast du das jemals gelöst? Ich habe das gleiche Problem – HypeZ

+0

@HypeZ Nein, es ist immer noch ein Problem. – Deanna

Antwort

2

Nun, ich hatte das gleiche Problem und nach ein paar Tagen der Forschung, Lesen ONVIF Dokumente und lernen ein paar Tipps über Multicasting, entwickelte ich diesen Code, der gut funktioniert. Als Beispiel die Haupt-IP-Adresse auf meinem Netzwerkadapter ist 192.168.80.55 und ich habe auch eine andere IP (192.168.0.10) in den erweiterten Einstellungen. Mit diesem Code kann ich den Geräte-Service einer Kamera mit der IP-Adresse 192.168.0.12 erkennen. Der wichtigste Teil dieses Beispiels ist die "DeepDiscovery" -Methode, die die Hauptidee der Iteration von Netzwerkadressen und der Multicasting-richtigen Probe-Nachricht enthält. Ich empfehle Deserialisierung der Antwort in "GetSocketResponse" -Methode. Derzeit extrahiere ich nur den Service-URI mit Regex.

Wie in diesem Artikel erwähnt (https://msdn.microsoft.com/en-us/library/dd456791(v=vs.110).aspx):

Für WCF Entdeckung richtig funktioniert, müssen alle NICs (Network Interface Controller) sollte 1 IP-Adresse nur.

ich die genaue Wirkung tue, die WS-Discovery-tut und mit Hilfe des Standard-3702-Anschluss, aber ich selbst den SOAP-Umschlag bauen und Socket-Klasse verwenden, um das Paket für alle IP-Adressen zu senden, die für die festgelegt wurden Netzwerkschnittstellen-Controller.

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

Das sieht vernünftig aus, aber ich bin nicht mehr in der Lage, das zu testen. Danke für die Antwort. – Deanna

Verwandte Themen