2013-03-07 16 views
5

Mam następujący kod do zapoznania multicast wiadomości pochodzących z sieci, dla określonego IP + portUDP: Odczyt danych ze wszystkich interfejsów sieciowych

private static void ReceiveMessages(int port, string ip, CancellationToken token) 
{ 
    Task.Factory.StartNew(() => 
     { 
      using (var mUdpClientReceiver = new UdpClient()) 
      { 
       var mReceivingEndPoint = new IPEndPoint(IPAddress.Any, port); 
       mUdpClientReceiver.ExclusiveAddressUse = false; 
       mUdpClientReceiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); 
       mUdpClientReceiver.ExclusiveAddressUse = false; 
       mUdpClientReceiver.Client.Bind(mReceivingEndPoint); 
       mUdpClientReceiver.JoinMulticastGroup(IPAddress.Parse(ip), 255); 

       while (!token.IsCancellationRequested) 
       { 
        byte[] receive = mUdpClientReceiver.Receive(ref mReceivingEndPoint); 

        Console.WriteLine("Message received from {0} ",mReceivingEndPoint); 
       } 
      } 
     }); 
} 

mam dwie karty sieciowe, z którego mam dane przychodzące na ten multicastowy port ip + (potwierdzone przez dwa wystąpienia monitorowania przez sieć Wireshark każdej karty sieciowej). Widzę na wireshark dużo ruchu przychodzącego na ten port + Ip) dla obu kart sieciowych.

Problem polega na tym, że na mojej konsoli widzę tylko wiadomości przychodzące z jednej karty sieciowej.

I podwójne sprawdzane netstat, nie mam żadnego innego oprogramowania słuchania na moim porcie: enter image description here

Więc Dlaczego otrzymuję od ruchu tylko jeden z moich dwóch kart sieciowych?

EDIT:

Próbowałem nawet, co następuje:

private static void ReceiveMessages(int port, string ip, CancellationToken token, IEnumerable<IPAddress> ipAddresses) 
{ 
    foreach (IPAddress ipAddress in ipAddresses) 
    { 
     IPAddress ipToUse = ipAddress; 
     Task.Factory.StartNew(() => 
     { 
      using (var mUdpClientReceiver = new UdpClient()) 
      { 

       var mReceivingEndPoint = new IPEndPoint(ipToUse, port); 
       mUdpClientReceiver.ExclusiveAddressUse = false; 
       mUdpClientReceiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); 
       mUdpClientReceiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); 
       mUdpClientReceiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1); 
       mUdpClientReceiver.ExclusiveAddressUse = false; 
       mUdpClientReceiver.Client.Bind(mReceivingEndPoint); 
       mUdpClientReceiver.JoinMulticastGroup(IPAddress.Parse(ip), 255); 
       Console.WriteLine("Starting to listen on "+ipToUse); 
       while (!token.IsCancellationRequested) 
       { 
        byte[] receive = mUdpClientReceiver.Receive(ref mReceivingEndPoint); 

        Console.WriteLine("Message received from {0} on {1}", mReceivingEndPoint,ipToUse); 
       } 
      } 
     }); 
    } 
} 

widzę „Uruchamianie słuchać na theCorrectIP” dwukrotnie (dla moich dwóch adresów IP), ale nadal wyświetla pochodzące wyłącznie dane z jednej karty sieciowej.

EDIT 2

Zauważyłem coś innego, co jest dziwne, zbyt. Jeśli wyłączę interfejs, na który otrzymuję wszystkie dane, a następnie uruchamiam oprogramowanie, otrzymuję teraz dane z innego interfejsu. Jeśli ponownie aktywuję interfejs i zrestartuję oprogramowanie, nadal otrzymuję ruch z niezajętej karty.

I wiem na pewno, że mam urządzeń, które odpowiadają mi, że są podłączone tylko do jednej sieci (nie oba)

EDIT 3

Kolejna rzecz: jeśli mogę wysłać wiadomość ode mnie (localhost), na całej mojej karcie sieciowej, widzę, że nadchodzą na moich dwóch interfejsach sieciowych. ALE jeśli uruchomię mój program dwa razy, tylko pierwszy program otrzyma wiadomości, a nie drugi.

Edycja 4

Dodatkowe info, po pierwszym komentarzu: mam dwie karty Ethernet, jeden z 10.10.24.78 IP, drugi z 10.9.10.234 ip. To nie ja wysyłam dane, ale elementy sieciowe (port 5353 z tym adresem IP jest znanym adresem multiemisji używanym dla mDNS, więc powinienem odbierać ruch z takich rzeczy jak drukarka, itunes, macs i inne utworzone przez nas oprogramowanie) . Dane są przesyłane multicastowo na adres ip 224.0.0.251 i port 5353.

Oto kod, który można użyć do wysyłania danych na różnych adresach IP, ale jak opisałem, jeśli uruchomisz go w lokalnym prawie działa (z wyjątkiem, że tylko jeden lokalny klient otrzymuje wiadomość).

private static void SendManuallyOnAllCards(int port, string multicastAddress, IEnumerable<IPAddress> ipAddresses) 
{ 
    foreach (IPAddress remoteAddress in ipAddresses) 
    { 
     IPAddress ipToUse = remoteAddress; 
     using (var mSendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) 
     { 
      mSendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, 
             new MulticastOption(IPAddress.Parse(multicastAddress))); 
      mSendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 255); 
      mSendSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); 

      var ipep = new IPEndPoint(ipToUse, port); 
      //IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(multicastAddress), port); 
      mSendSocket.Bind(ipep); 
      mSendSocket.Connect(ipep); 


      byte[] bytes = Encoding.ASCII.GetBytes("This is my welcome message"); 
      mSendSocket.Send(bytes, bytes.Length, SocketFlags.None); 
     } 
    } 
} 

EDIT 5 Oto wynik mojego route print (nie wiedziałem, że polecenia), a na moich dwóch adresów IP, zawsze otrzymują dane na temat 10.9.10.234 enter image description here

Edytuj 6

próbowałem kilka innych rzeczy:

  1. Użyj gniazdo otrzymywać zamiast UdpClient -> Nie działa
  2. ustawić kilka dodawania socketOption na czytniku (DontRoute = 1, Broadcast = 1) -> Nie działa
  3. Określ MulticastInterface że gniazdo czytnika musi używać (używając socketOption MulticastInterface) -> Nie działało
+0

Jakie są twoje interfejsy (ethernet, eth/wlan)? A jakie masz IP na tych interfejsach? Byłoby bardziej pomocne, gdybyś mógł przeanalizować, w jaki sposób wysyłasz wiadomość multiemisji. – PCoder

+0

@PCoder: Dzięki za komentarz, dodałem kilka szczegółów na temat mojego pierwszego pytania (Edit 4) – J4N

+0

Czy możesz pokazać nam wynik polecenia 'route print'? – PCoder

Odpowiedz

5

W końcu znalazłem, jak to zrobić!

W rzeczywistości, jeśli zachowam dokładnie ten sam kod, ale używając go z metodami asynchronicznymi, to działa !!! Po prostu nie mogę zrozumieć, dlaczego to nie działa z metodą synchronizacji (jeśli ktoś wie, możesz mi powiedzieć :))

Ponieważ straciłem 3 dni na tym, myślę, że warto przykład :

private static void ReceiveAsync(int port, string address, IEnumerable<IPAddress> localAddresses) 
{ 
    IPAddress multicastAddress = IPAddress.Parse(address); 
    foreach (IPAddress localAddress in localAddresses) 
    { 
     var udpClient = new UdpClient(AddressFamily.InterNetwork); 
     udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); 
     udpClient.Client.Bind(new IPEndPoint(localAddress, port)); 
     udpClient.JoinMulticastGroup(multicastAddress, localAddress); 
     udpClient.BeginReceive(OnReceiveSink, 
           new object[] 
            { 
             udpClient, new IPEndPoint(localAddress, ((IPEndPoint) udpClient.Client.LocalEndPoint).Port) 
            }); 
    } 
} 

I sposób asynchroniczny:

private static void OnReceiveSink(IAsyncResult result) 
{ 
    IPEndPoint ep = null; 
    var args = (object[]) result.AsyncState; 
    var session = (UdpClient) args[0]; 
    var local = (IPEndPoint) args[1]; 

    byte[] buffer = session.EndReceive(result, ref ep); 
    //Do what you want here with the data of the buffer 

    Console.WriteLine("Message received from " + ep + " to " + local); 

    //We make the next call to the begin receive 
    session.BeginReceive(OnReceiveSink, args); 
} 

mam nadzieję, że pomaga;)

2

Musisz dołączyć do grupy multiemisji za pośrednictwem wszystkich dostępnych interfejsów. Domyślnie wychodzący komunikat IGO JOIN będzie kierowany zgodnie z tabelami routingu emisji pojedynczej, które będą wysyłane przez "najtańszą" trasę, przy użyciu którejkolwiek karty sieciowej, która uzyska dostęp do tej trasy. Jeśli grupa multiemisji może być pobierana za pośrednictwem więcej niż jednej z tych tras, należy wykonać iterację.

+0

Nie jestem pewien, aby zrozumieć, 'mUdpClientReceiver.JoinMulticastGroup (IPAddress.Parse (ip), 255);', które jest zrobione dla wszystkich UdpClient to robi, nie? Jeśli nie, jak mam to zrobić? – J4N

+0

Musisz iterować po adresach IP lokalnych interfejsów i łączyć się z każdym z nich. – EJP

+1

Myślę, że nie widziałem mojego drugiego cytatu z kodu, to jest dokładnie to, co robię. – J4N

2

miałem ten sam problem, który chciałem otrzymać multicast ze wszystkich moich interfejsów sieciowych. Jak EJP już powiedziałem, trzeba zadzwonić JoinMulticastGroup(IPAddress multicastAddr, IPAddress localAddress) na UdpClient dla wszystkich interfejsów sieciowych:

int port = 1036; 
IPAddress multicastAddress = IPAddress.Parse("239.192.1.12"); 

client = new UdpClient(new IPEndPoint(IPAddress.Any, port)); 

// list of UdpClients to send multicasts 
List<UdpClient> sendClients = new List<UdpClient>(); 

// join multicast group on all available network interfaces 
NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); 

foreach (NetworkInterface networkInterface in networkInterfaces) 
{ 
    if ((!networkInterface.Supports(NetworkInterfaceComponent.IPv4)) || 
     (networkInterface.OperationalStatus != OperationalStatus.Up)) 
    { 
     continue; 
    } 

    IPInterfaceProperties adapterProperties = networkInterface.GetIPProperties(); 
    UnicastIPAddressInformationCollection unicastIPAddresses = adapterProperties.UnicastAddresses; 
    IPAddress ipAddress = null; 

    foreach (UnicastIPAddressInformation unicastIPAddress in unicastIPAddresses) 
    { 
     if (unicastIPAddress.Address.AddressFamily != AddressFamily.InterNetwork) 
     { 
      continue; 
     } 

     ipAddress = unicastIPAddress.Address; 
     break; 
    } 

    if (ipAddress == null) 
    { 
     continue; 
    } 

    client.JoinMulticastGroup(multicastAddress, ipAddress); 

    UdpClient sendClient = new UdpClient(new IPEndPoint(ipAddress, port)); 
    sendClients.Add(sendClient); 
} 

Ja również tworzenie listy UdpClients więc mogę wysłać moje multicast na wszystkich interfejsach sieciowych.

+0

Thnks, znalazłem to pomocne – KGCybeX

Powiązane problemy