2009-07-08 27 views
11

Necesito enviar un mensaje UDP a una dirección IP y puerto específicos.Transmitiendo un mensaje UDP a todas las tarjetas de red disponibles

Puesto que hay 3 tarjetas de red,

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

cuando envío un mensaje UDP, estoy recibiendo el mensaje sólo en un adaptador de red ... el resto de la década de IP no están recibiendo.

Quiero comprobar el adaptador de red mientras estoy enviando el mensaje. ¿Cómo puedo hacer eso?


Actualmente estoy usando el siguiente:

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

Puede aclarar más lo que está intentando desea-do. –

+0

Mi aplicación enviará mensajes a una aplicación en más de 10 sistemas. En el que todos los sistemas están en tres tarjetas de red diferentes. Como 10.1.x.x/10.2.x.x/10.4.x.x, puedo recibir el mensaje en una sola tarjeta de red 10.1.x.x pero no en otras dos tarjetas de red. Entonces quiero verificar la disponibilidad de la tarjeta de red y luego enviar el mensaje. Gracias. – Anuya

+0

así es el mensaje solo para verificar la disponibilidad de la red, o tiene alguna otra carga/significado? –

Respuesta

16

Esto es realmente más complicado de lo que parece, porque si tiene más de una interfaz, las transmisiones no siempre irán a todas las interfaces. Para evitar esto, creé esta clase.

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

} 

Luego, para enviar el paquete UDP por transmisión, utilizo algo como lo siguiente. Estoy usando IPAddress.Broadcast y MyUdpClient, que es diferente de su código.

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

Además, debe tener en cuenta que cuando se utiliza un ipaddress específica en lugar de la tabla de rutas de difusión sólo se envía fuera de la interfaz que coincide con la dirección.

Por lo tanto, en su ejemplo, se utiliza la unidifusión. Debe configurar LocalIP en la IP de la interfaz local que desea enviar. Con tres interfaces, tendrías tres IP locales y necesitas elegir la correcta para usar.

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

Como la ruta está desactivada, es posible que la vea en todas las interfaces, pero deberá probarla para el caso de unidifusión.

Si no le importa el IP o el puerto de envío, puede usar el siguiente código.

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

o para su difusión

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

El problema con IPAddress.Broadcast es que no lo harán ruta a través de las puertas de enlace. Para evitar esto, puede crear una lista de IPAddresses y luego recorrer y enviar. Además, dado que Send puede fallar por problemas de red que no puedes controlar, también debes tener un bloque 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 
} 

Editar: véase más arriba el cambio de unidifusión con múltiples interfaces y también Problem Trying to unicast packets to available networks.

+0

Hola Rex Logan, cuando probé el código ur, recibo el siguiente error: Se intentó una operación de socket para un host no alcanzable. Estoy confundido aquí, el adaptador de red con esa IP existe. cuando depuré la siguiente línea ... int numBytesSent = sendUdpClient.Send (CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint); vi targetEndPoint = {10.4.1.2:1982}. cuando targetEndPoint es {10.1.1.1:1982} estoy recibiendo el paquete en una máquina remota. ? :( – Anuya

+0

¿Qué pasa si usted envía a IPAddress.Broadcast Usted puede tratar de las versiones simplificadas que he ido añadiendo así –

+0

También puede intentar comentando s.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);. o s.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1) para ver qué ocurre –

1

Si va a enviar a una dirección IP específica, entonces se unicasting, no transmitir.

+0

Oh sí, eso es correcto. Pero me puse a seleccionar la red antes de enviar ¿verdad? – Anuya

+1

¿Estás tratando de enviar un paquete de cada tarjeta de red local a un host remoto con una sola tarjeta de red? Si intenta probar cada tarjeta de red, busque un host en esa red para enviar un mensaje a. Deje que el SO haga el enrutamiento para usted. –

+0

Pero el sistema operativo siempre está enrutando a la primera tarjeta de red 10.1.x.x – Anuya

0

Expansión de respuesta de Rex. Esto le permite no tener que codificar las direcciones IP que desea transmitir. Pasa por todas las interfaces, comprueba si están activas, se asegura de que tenga información IPv4 y una dirección IPv4 asociada. Simplemente cambie la variable "data" a cualquier dato que desee transmitir, y el puerto "target" a aquel que desee.El pequeño inconveniente es que si una interfaz tiene múltiples direcciones IP asociadas, se transmitirá desde cada dirección. Nota: esto TAMBIÉN intentará enviar difusiones a través de cualquier adaptador VPN (a través del Centro de redes y recursos compartidos/Conexiones de red, se verificará Win 7+), y si desea recibir respuestas, deberá guardar todos los clientes. Tampoco necesitarás una clase secundaria.

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

He resuelto este problema mediante el envío de la difusión UDP de cada adaptador (usando 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; 
} 
Cuestiones relacionadas