2009-07-08 2 views
11

Мне нужно отправить сообщение UDP на определенные IP-адреса и порт.Передача сообщения UDP всем доступным сетевым картам

Поскольку есть 3 сетевые карты,

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

когда я отправить сообщение UDP, я получаю сообщение только в одном сетевом адаптере ... остальные IP-адресов, которые не получают.

Я хочу проверить сетевой адаптер при отправке сообщения. Как я могу это сделать?


В настоящее время я использую следующие:

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

Вы можете уточнить больше, что вы хотите пытаетесь дел. –

+0

Мое приложение отправит сообщения в приложение в 10+ системах. В которых все системы находятся в трех разных сетевых картах. Как 10.1.x.x/10.2.x.x/10.4.x.x Я могу получить сообщение только в одной сетевой карте 10.1.x.x, но не в других двух сетевых картах. Поэтому я хочу проверить доступность сетевой карты, а затем отправить сообщение. Благодарю. – Anuya

+0

, так это сообщение, нужно только проверить доступность сети или иметь какую-то другую полезную нагрузку/смысл? –

ответ

16

Это на самом деле сложнее, чем кажется, потому что, если у вас более одного интерфейса, широковещательные передачи не всегда выходят на все интерфейсы. Чтобы обойти это, я создал этот класс.

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

} 

Затем, чтобы отправить UDP-пакет через широковещательную рассылку, я использую что-то вроде следующего. Я использую IPAddress.Broadcast и MyUdpClient, который отличается от вашего кода.

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

Кроме того, следует отметить, что при использовании конкретного ipaddress вместо трансляции таблица маршрутизации только отправляет его через интерфейс, соответствующий адрес.

В вашем примере используется одноадресная рассылка. Вам нужно установить LocalIP на IP-адрес локального интерфейса, который вы хотите отправить. С тремя интерфейсами у вас будет три локальных IP-адреса, и вам нужно выбрать правильный для использования.

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

Поскольку маршрут отключен, вы можете увидеть его на всех интерфейсах, но вам нужно будет протестировать его для случая одноадресной передачи.

Если вам не нужен IP-адрес отправки, вы можете использовать следующий код.

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

или для трансляции

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

Проблема с IPAddress.Broadcast том, что они не будут маршрут через любые шлюзы. Чтобы обойти это, вы можете создать список IPAddresses, а затем выполнить цикл и отправить. Кроме того, поскольку Send может выйти из строя для сетевых проблем, которые вы не можете контролировать, также должен быть блок 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: см.выше изменения в одноадресно с несколькими интерфейсами, а также Problem Trying to unicast packets to available networks.

+0

Hi Rex Logan, Когда я попытался ур код, я получаю следующую ошибку: Операция сокета была предпринята для невосстановимого хоста. Я запутался здесь, сетевой адаптер с этим IP существует. , когда я отлаживал нижнюю строку ... int numBytesSent = sendUdpClient.Send (CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint); Я увидел targetEndPoint = {10.4.1.2:1982}. Когда targetEndPoint {10.1.1.1:1982}, я получаю пакет на удаленной машине. ? :( – Anuya

+0

Что произойдет, если вы отправляете IPAddress.Broadcast Вы можете попробовать упрощенные версии я добавил, а –

+0

Вы также можете попробовать закомментировать s.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);. или s.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1) , чтобы посмотреть, что произойдет –

1

Если вы отправляете на определенный IP-адрес, то вы одноадресной, не транслирует.

+0

О да, верно. Но я выбираю сеть перед отправкой? – Anuya

+1

А вы пытаетесь отправить пакет с каждой локальной сетевой карты на удаленный хост с помощью одной сетевой карты? Если вы попытаетесь протестировать каждую сетевую карту, найдите хост в этой сети для отправки сообщения. Позвольте ОС выполнить маршрутизацию для вас. –

+0

Но ОС всегда маршрутизируется на первую сетевую карту 10.1.x.x – Anuya

0

Расширение Ответ Рекса. Это позволяет вам не требовать жесткого кодирования IP-адресов, которые вы хотите транслировать. Перебирает все интерфейсы, проверяет, если они установлены, удостоверяется, что у него есть информация IPv4, и с ним связан IPv4-адрес. Просто измените переменную «данные» на любые данные, которые вы хотите передать, и «целевой» порт на тот, который вы хотите.Небольшой недостаток заключается в том, что если интерфейс имеет несколько связанных с ним IP-адресов, он будет транслировать данные из каждого адреса. Примечание. Это также будет пытаться отправлять широковещательные сообщения через любой VPN-адаптер (через Network and Sharing Center/Network Connections, Win 7+ verified), и если вы хотите получать ответы, вам нужно будет сохранить всех клиентов. Вам также не понадобится дополнительный класс.

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

Я решил эту проблему путем отправки трансляции UDP от каждого адаптера (используя привязку):

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; 
} 
Смежные вопросы