Почему многоадресная рассылка UDP не достигает машин в сети? - PullRequest
1 голос
/ 27 октября 2010

Я пытаюсь настроить автоматическое обнаружение с использованием многоадресной передачи UDP и использую некоторый пример кода из Интернета.Кажется, это работает нормально, когда я запускаю клиент и сервер на одной машине, но когда я запускаю их на разных машинах, либо с машиной, работающей в виртуальной машине на моем компьютере (virtualBox), либо на других «реальных» машинах насеть, тогда другие машины, кажется, никогда не получают сообщения, передаваемые в широковещательном режиме.

После некоторого поиска в Google кажется вероятным виновником будет маршрутизатор (SpeedTouch 780), который может отбрасывать пакеты.Как я могу проверить, так ли это?Есть ли у них другие вещи, которые я могу проверить, чтобы попытаться отследить проблему?Может ли это быть что-то совсем другое?

код:

код сервера

using System;
using System.Net.Sockets;
using System.Text;

internal class StockPriceMulticaster
    {
    private static string[] symbols = {"ABCD", "EFGH", "IJKL", "MNOP"};

    public static void Main ()
        {
        using (UdpClient publisher = new UdpClient ("230.0.0.1", 8899))
            {
            Console.WriteLine ("Publishing stock prices to 230.0.0.1:8899");
            Random gen = new Random ();
            while (true)
                {
                int i = gen.Next (0, symbols.Length);
                double price = 400*gen.NextDouble () + 100;
                string msg = String.Format ("{0} {1:#.00}", symbols, price);
                byte[] sdata = Encoding.ASCII.GetBytes (msg);
                publisher.Send (sdata, sdata.Length);
                System.Threading.Thread.Sleep (5000);
                }
            }
        }
    }

и клиент:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class StockPriceReceiver{
    public static void Main(){
        UdpClient subscriber = new UdpClient(8899);
        IPAddress addr = IPAddress.Parse("230.0.0.1");
        subscriber.JoinMulticastGroup(addr);
        IPEndPoint ep = null;
        for(int i=0; i<10;i++){
            byte[] pdata = subscriber.Receive(ref ep);
            string price = Encoding.ASCII.GetString(pdata);
            Console.WriteLine(price);
        }
        subscriber.DropMulticastGroup(addr);
    }
}

РЕДАКТИРОВАТЬ

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

Ответы [ 5 ]

5 голосов
/ 28 октября 2010

Таким образом, проблема заключалась в том, что, поскольку у меня было более 1 активного сетевого подключения, оно выбирало одно и использовало его, что вызывало отправку пакетов UDP по другому сетевому подключению, которое прослушивал клиент. Поскольку я установил Virtual box, он установил и активировал сетевой адаптер VirtualBox только для хоста, так что можно было поддерживать только сетевые соединения хоста. Когда я переключил VirtualBox в режим только хост, пакеты начали приниматься. Отключение адаптера VirtualBox и переключение обратно на мостовое соединение также работало.

2 голосов
/ 14 декабря 2012

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

Вот как я реализовал службу обнаружения UDP. Первоначально он сломался, потому что мои интерфейсы Virtual Box мешали и поглощали широковещательные рассылки UDP в случайной IP-подсети (192.168.56.x) вместо моего фактического соединения с Ethernet (192.168.0.x). Так что я улучшил его, основываясь на ответе Гуге. Это немного многословно, и я, вероятно, не очень аккуратно его кодировал, но теперь это работает. Я транслирую на все интерфейсы, потом получать данные (циклический перебор) по всем интерфейсам до истечения времени ожидания или одного ответа (если justFindOne = true).

По какой-то причине интерфейсы IPv6 вызывают сбой в части UDP, поэтому я просто отфильтрую адреса IPv4. Пожалуйста, поправьте меня, если есть способ, чтобы это работало на обоих.

    const int iPort = 7611;
    const int IP_TIMEOUT = 1000;

    private static List<DiscoveryServer> FindIPAddresses(string filter, bool justFindOne)
    {
        List<DiscoveryServer> ipNames = new List<DiscoveryServer>();

        byte[] message = new byte[2] { 17, 2 };
        string hostname = Dns.GetHostName();
        IPHostEntry entry = Dns.GetHostEntry(hostname);
        List<UdpClient> clients = new List<UdpClient>();

        try
        {
            // send out UDP packets on all IPv4 interfaces.

            foreach (var ipAddress in entry.AddressList)
            {
                if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
                {
                    IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, iPort);

                    UdpClient udpC = new UdpClient(ipLocalEndPoint);
                    clients.Add(udpC);
                    udpC.EnableBroadcast = true;
                    udpC.Client.ReceiveTimeout = IP_TIMEOUT;
                    int response1 = udpC.Send(message, 2, new IPEndPoint(IPAddress.Broadcast, iPort));
                }
            }

            if (clients.Count == 0)
            {
                throw new Exception("There are no IPv4 network interfaces available");
            }

            System.DateTime startTime = System.DateTime.Now;
            double timeout = IP_TIMEOUT / 1000;

            IPEndPoint remEP = new IPEndPoint(IPAddress.Broadcast, iPort);

            while (System.DateTime.Now.Subtract(startTime) < TimeSpan.FromSeconds(timeout) &&
                !(justFindOne && ipNames.Count() > 0))
            {
                foreach (var udpC in clients)
                {
                    if (udpC.Available > 0)
                    {
                        byte[] response = udpC.Receive(ref remEP);
                        string name;
                        if (response.Length > 2)
                        {
                            name = System.Text.Encoding.ASCII.GetString(response, 3, response[2]);
                            if (filter == "" || name.Contains(filter))
                            {
                                DiscoveryServer ds = new DiscoveryServer(name, remEP.Address);
                                ipNames.Add(ds);
                                if (justFindOne) break;
                            }
                        }
                    }
                }
            }
        }
        finally
        {
            foreach (var udpC in clients)
            {
                udpC.Close();
            }
        }
        return ipNames;

    }
1 голос
/ 20 сентября 2012

В своем коде вы не настраиваете TTL для своего звонка в UdpClient.Поэтому, если TTL по умолчанию равен 1, ваши пакеты не пройдут первый маршрутизатор.

1 голос
/ 27 октября 2010

Здесь нужно рассмотреть несколько вопросов.

Первый: вы уверены, что многоадресная рассылка - лучший способ сделать это?Я думаю, что широковещательная рассылка послужит вам лучше.

С другой стороны: маршрутизаторы обычно не пересылают многоадресную или широковещательную рассылку, а коммутаторы и концентраторы.

Взгляните на следующие два вопроса:* Почему (многоадресные UDP-пакеты) не принимаются? и многоадресная UDP-передача по Интернету?

РЕДАКТИРОВАТЬ:

При создании клиента UdpClient вы можете указатьс какой локальной конечной точки вы будете отправлять.http://msdn.microsoft.com/en-us/library/k227d11f.aspx

1 голос
/ 27 октября 2010

Я бы попробовал Wireshark .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...