2009-07-08 11 views
11

Muszę wysłać wiadomość UDP do określonego adresu IP i portu.Rozsyłanie komunikatu UDP do wszystkich dostępnych kart sieciowych

Ponieważ istnieją 3 kart sieciowych,

10.1.x.x 
10.2.x.x 
10.4.x.x 

kiedy wysłać wiadomość UDP, otrzymuję komunikat tylko w jedną kartę sieciową ... reszta IP nie otrzymują.

Chcę sprawdzić kartę sieciową podczas wysyłania wiadomości. Jak mogę to zrobić?


Obecnie używam następujący:

IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(LocalIP), 0); 
IPEndPoint targetEndPoint = new IPEndPoint(TargetIP, iTargetPort); 
UdpClient sendUdpClient = new UdpClient(localEndPoint); 
int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint); 
+0

można wyjaśnić więcej czego chcą próby zrobienia. –

+0

Moja aplikacja wyśle ​​wiadomości do aplikacji w ponad 10 systemach. W którym wszystkie systemy są na trzech różnych kartach sieciowych. Podobnie jak 10.1.x.x/10.2.x.x/10.4.x.x mogę odebrać wiadomość tylko na jednej karcie sieciowej 10.1.x.x, ale nie na dwóch innych kartach sieciowych. Dlatego chcę sprawdzić dostępność karty sieciowej, a następnie wysłać wiadomość. Dzięki. – Anuya

+0

, więc czy wiadomość ma tylko sprawdzić dostępność sieci, czy ma jakiś inny ładunek/znaczenie? –

Odpowiedz

16

To jest rzeczywiście trudniejsze, niż się wydaje, ponieważ jeśli masz więcej niż jeden interfejs, transmisje nie zawsze wychodzą na wszystkie interfejsy. Aby obejść ten problem, stworzyłem tę klasę.

public class MyUdpClient : UdpClient 
{ 
    public MyUdpClient() : base() 
    { 
     //Calls the protected Client property belonging to the UdpClient base class. 
     Socket s = this.Client; 
     //Uses the Socket returned by Client to set an option that is not available using UdpClient. 
     s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); 
     s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1); 
    } 

    public MyUdpClient(IPEndPoint ipLocalEndPoint) : base(ipLocalEndPoint) 
    { 
     //Calls the protected Client property belonging to the UdpClient base class. 
     Socket s = this.Client; 
     //Uses the Socket returned by Client to set an option that is not available using UdpClient. 
     s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); 
     s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1); 
    } 

} 

Następnie wysłać pakiet UDP za pośrednictwem transmisji używam coś jak poniżej. Używam IPAddress.Broadcast i MyUdpClient, która różni się od Twojego kodu.

IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(LocalIP), 0); 
IPEndPoint targetEndPoint = new IPEndPoint(IPAddress.Broadcast, iTargetPort); 
MyUdpClient sendUdpClient = new MyUdpClient(localEndPoint); 
int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint); 

Ponadto, należy pamiętać, że podczas korzystania z konkretnego ipaddress zamiast transmisji tabela trasa tylko wysyła go do interfejsu, który pasuje do adresu.

Tak więc w twoim przykładzie użyto unicast. Musisz ustawić LocalIP na adres IP lokalnego interfejsu, do którego chcesz wysłać. Dzięki trzem interfejsom będziesz miał trzy lokalne adresy IP i musisz wybrać właściwy, którego chcesz użyć.

IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(LocalIP), 0); 
IPEndPoint targetEndPoint = new IPEndPoint(TargetIP, iTargetPort); 
MyUdpClient sendUdpClient = new MyUdpClient(localEndPoint); 
int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint); 

Ponieważ trasa jest wyłączony można go zobaczyć na wszystkich interfejsach, ale trzeba będzie to sprawdzić w przypadku emisji pojedynczej.

Jeśli nie zależy Ci na wysłaniu adresu IP lub portu, możesz użyć następującego kodu.

IPEndPoint targetEndPoint = new IPEndPoint(TargetIP, iTargetPort); 
MyUdpClient sendUdpClient = new MyUdpClient(); 
int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint); 

lub audycji

IPEndPoint targetEndPoint = new IPEndPoint(IPAddress.Broadcast, iTargetPort); 
MyUdpClient sendUdpClient = new MyUdpClient(); 
int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint); 

problem z IPAddress.Broadcast jest to, że nie będzie żadnej trasy przez bramy. Aby obejść ten problem, można utworzyć listę IPAddresses, a następnie wykonać pętlę i wysłać. Także ponieważ Send może zawieść w przypadku problemów sieciowych, nad którymi nie możesz kontrolować, powinieneś także mieć blok try/catch.

ArrayList ip_addr_acq = new ArrayList(); 

ip_addr_acq.Add(IPAddress.Parse("10.1.1.1")); // add to list of address to send to 

try 
{ 
    foreach (IPAddress curAdd in ip_addr_acq) 
    { 
     IPEndPoint targetEndPoint = new IPEndPoint(curAdd , iTargetPort); 
     MyUdpClient sendUdpClient = new MyUdpClient(); 
     int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint); 

     Thread.Sleep(40); //small delay between each message 
    } 
} 
catch 
{ 
// handle any exceptions 
} 

Edit: patrz wyżej zmianę do emisji pojedynczej z wielu interfejsów i również Problem Trying to unicast packets to available networks.

+0

Cześć Rex Logan, Kiedy próbowałem ur kodu, otrzymuję następujący błąd: Operacja gniazda została podjęta próba hosta niewymagalnego. Jestem tu zdezorientowany, istnieje adapter sieciowy z tym adresem IP. po debugowaniu poniższej linii ... int numBytesSent = sendUdpClient.Send (CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint); Widziałem targetEndPoint = {10.4.1.2:1982}. kiedy targetEndPoint jest {10.1.1.1:1982} otrzymuję pakiet na zdalnym komputerze. ? :( – Anuya

+0

Co się stanie, jeśli wyślesz do IPAddress.Broadcast Można spróbować uproszczone wersje I dodał także –

+0

też może spróbować zakomentowanie s.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);. lub s.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1) , aby zobaczyć, co się stanie –

1

Jeśli wysyłasz do konkretnego adresu IP, to jesteś wysyłania jednostkowego, a nie nadawanie.

+0

O tak, tak jest. Ale czy wybieram sieć przed wysłaniem w prawo? – Anuya

+1

Ah próbujesz wysłać pakiet z każdej lokalnej karty sieciowej do zdalnego hosta za pomocą jednej karty sieciowej? Jeśli próbujesz przetestować każdą kartę sieciową, znajdź hosta w tej sieci, do którego chcesz wysłać wiadomość. Niech system operacyjny wykona dla ciebie routing. –

+0

Ale system operacyjny zawsze kieruje się do pierwszej karty sieciowej 10.1.x.x – Anuya

0

Rozbudowa Rexa Odpowiedź. Dzięki temu nie musisz sztywno kodować adresów IP, które chcesz transmitować. Pętle przechodzą przez wszystkie interfejsy, sprawdzają, czy są w górze, upewnia się, że ma informacje IPv4, i powiązany jest z nim adres IPv4. Po prostu zmień zmienną "data" na dowolne dane, które chcesz transmitować, a port "docelowy" na ten, który chcesz.Niewielką wadą jest to, że jeśli interfejs ma wiele adresów IP powiązanych z nim, będzie nadawać z każdego adresu. Uwaga: to również spróbuje wysłać transmisje za pośrednictwem dowolnego adaptera VPN (za pośrednictwem sieci i centrum udostępniania/połączeń sieciowych, zweryfikowanego przez Win 7+), a jeśli chcesz otrzymywać odpowiedzi, będziesz musiał zapisać wszystkich klientów. Nie będziesz także potrzebował dodatkowej klasy.

foreach(NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces()) { 
     if(ni.OperationalStatus == OperationalStatus.Up && ni.SupportsMulticast && ni.GetIPProperties().GetIPv4Properties() != null) { 
      int id = ni.GetIPProperties().GetIPv4Properties().Index; 
      if(NetworkInterface.LoopbackInterfaceIndex != id) { 
       foreach(UnicastIPAddressInformation uip in ni.GetIPProperties().UnicastAddresses) { 
        if(uip.Address.AddressFamily == AddressFamily.InterNetwork) { 
         IPEndPoint local = new IPEndPoint(uip.Address.Address, 0); 
         UdpClient udpc = new UdpClient(local); 
         udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); 
         udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1); 
         byte[] data = new byte[10]{1,2,3,4,5,6,7,8,9,10}; 
         IPEndPoint target = new IPEndPoint(IPAddress.Broadcast, 48888); 
         udpc.Send(data,data.Length, target); 
        } 
       } 
      } 
     } 
    } 
0

I rozwiązać ten problem poprzez wysyłanie transmisji UDP z każdej karty (za pomocą wiązania):

public static void SNCT_SendBroadcast(out List<MyDevice> DevicesList) 
{ 
DevicesList = new List<MyDevice>(); 
byte[] data = new byte[2]; //broadcast data 
data[0] = 0x0A; 
data[1] = 0x60; 

IPEndPoint ip = new IPEndPoint(IPAddress.Broadcast, 45000); //braodcast IP address, and corresponding port 

NetworkInterface[] nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces(); //get all network interfaces of the computer 

foreach (NetworkInterface adapter in nics) 
{ 
// Only select interfaces that are Ethernet type and support IPv4 (important to minimize waiting time) 
if (adapter.NetworkInterfaceType != NetworkInterfaceType.Ethernet) { continue; } 
if (adapter.Supports(NetworkInterfaceComponent.IPv4) == false) { continue; } 
try 
{ 
    IPInterfaceProperties adapterProperties = adapter.GetIPProperties();  
    foreach (var ua in adapterProperties.UnicastAddresses) 
    { 
     if (ua.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) 
     { 
     //SEND BROADCAST IN THE ADAPTER 
      //1) Set the socket as UDP Client 
      Socket bcSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //broadcast socket 
      //2) Set socker options 
      bcSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); 
      bcSocket.ReceiveTimeout = 200; //receive timout 200ms 
      //3) Bind to the current selected adapter 
      IPEndPoint myLocalEndPoint = new IPEndPoint(ua.Address, 45000); 
      bcSocket.Bind(myLocalEndPoint); 
      //4) Send the broadcast data 
      bcSocket.SendTo(data, ip); 

     //RECEIVE BROADCAST IN THE ADAPTER 
      int BUFFER_SIZE_ANSWER = 1024; 
      byte[] bufferAnswer = new byte[BUFFER_SIZE_ANSWER]; 
      do 
      { 
       try 
       { 
        bcSocket.Receive(bufferAnswer); 
        DevicesList.Add(GetMyDevice(bufferAnswer)); //Corresponding functions to get the devices information. Depends on the application. 
       } 
       catch { break; } 

      } while (bcSocket.ReceiveTimeout != 0); //fixed receive timeout for each adapter that supports our broadcast 
      bcSocket.Close(); 
     } 
    } 
    } 
    catch { } 
} 
return; 
} 
Powiązane problemy