2009-07-08 5 views
11

Devo inviare un messaggio UDP a IP e porta specifici.Trasmissione messaggio UDP a tutte le schede di rete disponibili

Dal momento che ci sono 3 schede di rete,

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

Quando si invia un messaggio UDP, sto ricevendo il messaggio in una sola scheda di rete ... il resto degli ip di non ricevono.

Desidero controllare la scheda di rete durante l'invio del messaggio. Come lo posso fare?


Attualmente sto usando il seguente:

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

Può chiarire di più ciò che si sta tentando desidera to-do. –

+0

La mia applicazione invierà messaggi a un'applicazione in più di 10 sistemi. In cui tutti i sistemi sono in tre diverse schede di rete. Come 10.1.x.x/10.2.x.x/10.4.x.x sono in grado di ricevere il messaggio in una sola scheda di rete 10.1.x.x ma non in altre due schede di rete. Quindi voglio verificare la disponibilità della scheda di rete e quindi inviare il messaggio. Grazie. – Anuya

+0

quindi il messaggio deve solo verificare la disponibilità della rete o ha qualche altro payload/significato? –

risposta

16

Questo è in realtà più complicato di quanto possa sembrare, perché se si dispone di più di un'interfaccia, le trasmissioni non si diffonderanno sempre su tutte le interfacce. Per aggirare questo ho creato questa classe.

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

} 

Quindi per inviare il pacchetto UDP via broadcast, io uso qualcosa come il seguente. Sto usando IPAddress.Broadcast e MyUdpClient, che è diverso dal tuo codice.

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

Inoltre, si dovrebbe notare che quando si utilizza una specifica ipaddress invece di trasmissione della tabella di route invia solo fuori l'interfaccia che corrisponde all'indirizzo.

Così nel tuo esempio, viene usato unicast. È necessario impostare LocalIP sull'IP dell'interfaccia locale a cui si desidera inviare. Con tre interfacce, avresti tre IP locali e devi scegliere quello corretto da utilizzare.

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

Perché percorso è spento si potrebbe vedere su tutte le interfacce, ma sarà necessario per testare questo per il caso unicast.

Se non ti interessa l'IP o la porta di invio, puoi utilizzare il seguente codice.

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

o per la trasmissione

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

Il problema con IPAddress.Broadcast è che non lo faranno percorso attraverso qualsiasi gateway. Per aggirare questo è possibile creare un elenco di IPAddresses e quindi eseguire il ciclo e inviare. Inoltre, poiché Send può fallire per problemi di rete che non puoi controllare, dovresti anche avere un blocco 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: vedi sopra cambiamento trasmettere in unicast con interfacce multiple e anche Problem Trying to unicast packets to available networks.

+0

Hi Rex Logan, quando ho provato il codice ur, ricevo il seguente errore: Un'operazione socket è stata tentata su un host irraggiungibile. Sono confuso qui, la scheda di rete con quell'IP esiste. quando ho eseguito il debug della riga sottostante ... int numBytesSent = sendUdpClient.Send (CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint); ho visto targetEndPoint = {10.4.1.2:1982}. quando targetEndPoint è {10.1.1.1:1982} sto ricevendo il pacchetto nella macchina remota. ? :( – Anuya

+0

Che cosa succede se si invia a IPAddress.Broadcast Si potrebbe provare le versioni semplificate ho aggiunto pure –

+0

Si potrebbe anche provare commentando s.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);. oppure s.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1) per vedere cosa succede –

1

Se si invia a un indirizzo IP specifico poi si sono unicast, non trasmettendo.

+0

Oh sì sì. Ma devo selezionare la rete prima di mandare a destra? – Anuya

+1

Si sta tentando di inviare un pacchetto a ciascuna scheda di rete locale a un host remoto con una singola scheda di rete? Se provi a testare ciascuna scheda di rete, trova un host su quella rete a cui inviare un messaggio. Lascia che il sistema operativo esegua il routing per te. –

+0

Ma il sistema operativo è sempre in routing sulla prima scheda di rete 10.1.x.x – Anuya

0

espansione della risposta di Rex. Ciò ti consente di non dover codificare gli indirizzi IP su cui desideri trasmettere. Passa attraverso tutte le interfacce, controlla se sono attive, si assicura che disponga di informazioni IPv4 e ad esso sia associato un indirizzo IPv4. Basta cambiare la variabile "dati" con qualsiasi dato che si desidera trasmettere e la porta "target" su quella desiderata.Piccolo inconveniente è che se un'interfaccia ha più indirizzi IP associati, verrà trasmessa da ciascun indirizzo. Nota: questo tenterà ANCHE di inviare le trasmissioni tramite qualsiasi adattatore VPN (tramite Network and Sharing Center/Connessioni di rete, Win 7+ verificato) e se si desidera ricevere risposte, sarà necessario salvare tutti i client. Inoltre non avrai bisogno di una lezione secondaria.

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

Ho risolto questo problema con l'invio della trasmissione UDP da ciascuna scheda (utilizzando bind):

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; 
}