Вопрос по udpclient, c#, udp, multihomed – Трансляция UDP-сообщения на все доступные сетевые карты

11

Мне нужно отправить UDP-сообщение на определенный IP-адрес и порт.

Так как есть 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);
Можете ли вы уточнить, что вы хотите попробовать сделать? Simeon Pilgrim
так что сообщение должно просто проверять доступность сети, или оно имеет какую-то другую полезную нагрузку / значение? Simeon Pilgrim
Если вы пытаетесь получить избыточность, для случая, когда отправка подключена к сети A, но приемник отключен от A, но подключен к B и C (из-за сбоя сетевой карты / кабеля), и вы хотите, чтобы ваше сообщение поступило на получатель затем отправляет его, как говорит Рекс, должен сделать свое дело, но вам придется управлять дубликатом и, возможно, обработкой не по порядку на принимающей стороне. Simeon Pilgrim
Если вы просто хотите проверить возможность подключения каждого хоста из всех сетей, отправьте одноадресное сообщение на сетевой адрес хоста в каждой сети A, B и C. Simeon Pilgrim
Мое приложение будет отправлять сообщения в приложение в более 10 системах. В котором все системы находятся в трех разных сетевых картах. Как и 10.1.x.x / 10.2.x.x / 10.4.x.x, я могу получить сообщение только в одной сетевой карте 10.1.x.x, но не в двух других сетевых картах. Поэтому я хочу проверить наличие сетевой карты, а затем отправить сообщение. Благодарю. Anuya

Ваш Ответ

4   ответа
0

отправив широковещательную рассылку UDP от каждого адаптера (используя 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;
}
1

ния IP-адресов, по которым вы хотите транслировать. Проходит через все интерфейсы, проверяет их работоспособность, проверяет, есть ли у него информация IPv4 и с ним связан адрес IPv4. Просто измените & quot; данные & quot; переменная для любых данных, которые вы хотите транслировать, и & quot; target & quot; порт на тот, который вы хотите. Небольшой недостаток заключается в том, что если с интерфейсом связано несколько IP-адресов, он будет транслироваться с каждого адреса. Примечание: это также будет пытаться отправлять широковещательные сообщения через любой адаптер VPN (через Центр управления сетями и общим доступом / Сетевые подключения, Win 7+ проверено), и если вы хотите получать ответы, вам придется сохранить все клиенты. Вам также не понадобится второй класс.

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

то вы не используете широковещательную рассылку.

Ах да, это верно. Но я должен выбрать сеть перед отправкой, верно? Anuya
Если вы хотите отправить разные адреса Nic на разные адреса хостов. Это если они все в трех сетях. Это сводится к тому, чего вы пытаетесь достичь, проверяя сетевое подключение или отправляя реальное сообщение более высокого уровня.
Но ОС всегда маршрутизирует на первую сетевую карту 10.1.x.x Anuya
А вы пытаетесь отправить пакет с каждой локальной сетевой карты на удаленный хост с одной сетевой картой? Если вы пытаетесь проверить каждую сетевую карту, найдите хост в этой сети, чтобы отправить сообщение. Пусть ОС сделает маршрутизацию за вас.
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 а затем перебрать и отправить. Кроме того, поскольку отправка может привести к сбою при проблемах сети, которые вы не можете контролировать, у вас также должен быть блок 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
 }

Изменить: см. Выше изменение одноадресной передачи с несколькими интерфейсами, а такжеПроблема Попытка одноадресных пакетов в доступные сети.

Что произойдет, если вы отправите IPAddress.Broadcast? Вы также можете попробовать упрощенные версии, которые я добавил.
Это то же самое. мог найти этот IP. Я попытался пропинговать 10.4.1.2, но там написано "Хост назначения недоступен". Так что теперь это проблема сети или проблема приложения? Благодарю. Anuya
когда я делаю ipaddress.broadcast, я не получаю пакет на удаленной машине. Anuya
Привет, Рекс Логан, когда я попробовал ваш код, я получаю следующую ошибку: Операция с сокетом была предпринята для недоступного хоста. Я тут запутался, сетевой адаптер с таким IP существует. когда я отлаживал нижеприведенную строку ... int numBytesSent = sendUdpClient.Send (CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint); я увидел targetEndPoint = {10.4.1.2:1982}. когда targetEndPoint равен {10.1.1.1:1982}, я получаю пакет на удаленной машине. :( Anuya
Вы также можете попробовать закомментировать s.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1); или s.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1), чтобы увидеть, что происходит

Похожие вопросы