代码之家  ›  专栏  ›  技术社区  ›  Sam Holder Brian Adams

为什么我的UDP多播无法到达网络上的计算机?

  •  1
  • Sam Holder Brian Adams  · 技术社区  · 14 年前

    我正在尝试使用UDP多播设置自动发现,并使用一些来自Internet的示例代码。当我在同一台机器上运行客户机和服务器时,这似乎可以正常工作,但是当我在不同的机器上运行它们时,无论是在我的机器(virtualbox)上的虚拟机上运行的机器,还是在网络上的其他“真实”机器上运行的机器,其他机器似乎从未接收到bro的消息。广告。

    在谷歌搜索之后,可能的罪魁祸首是路由器(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数据包,而不是所有机器所连接的无线网络。只需要弄清楚怎么做就行了… 所以在答案中添加了解决方案…

    5 回复  |  直到 12 年前
        1
  •  5
  •   Sam Holder Brian Adams    14 年前

    所以问题是,由于我有一个以上的活动网络连接,它选择了一个并使用它,这导致UDP数据包在客户端监听的另一个网络连接上被发送出去。因为我安装了虚拟机,所以它安装并激活了仅限虚拟机的网络适配器,这样就可以支持仅限主机的网络连接。当我将virtualbox切换到仅主机模式时,数据包开始被接收。禁用virtualbox适配器并切换回桥接连接也有效。

        2
  •  2
  •   Mark Lakata    12 年前

    如果有多个接口, 正确的 答案是听所有的,如果你对什么是正确的没有一个定义,就不要试图选择一个。

    下面是我如何实现一个UDP发现服务。最初,它中断了,因为我的虚拟机接口挡住了路,吞没了随机IP子网(192.168.56.x)上的UDP广播,而不是我的实际以太网连接(192.168.0.x)。所以我改进了它,基于Guge的回答。这有点冗长,我可能没有用最简洁的方式编写代码,但现在可以工作了。我在所有接口上广播,然后 接收所有接口上的数据(循环),直到超时,或单个响应(如果 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;
    
        }
    
        3
  •  1
  •   Ladlestein    14 年前

    我会试试的 Wireshark .

        4
  •  1
  •   Community CDub    8 年前

    这里有几个问题需要研究。

    第一个问题是:你确定多播是最好的方式吗?我认为广播对你更有帮助。

    另一个是:路由器通常不转发多播或广播,交换机和集线器也不转发。

    请看以下两个问题: Why are (UDP multicast) packets not being received? UDP Multicast over the internet?

    编辑:

    创建UDPClient时,可以指定从哪个本地端点发送。 http://msdn.microsoft.com/en-us/library/k227d11f.aspx

        5
  •  1
  •   Peladao    12 年前

    在您的代码中,您不设置调用udpclient的TTL。因此,如果默认的TTL是1,那么您的数据包就不会通过第一个路由器。