【问题标题】:Why are my UDP multicast not reaching machines on the network?为什么我的 UDP 多播没有到达网络上的机器?
【发布时间】:2010-10-27 19:33:51
【问题描述】:

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

经过一番谷歌搜索,罪魁祸首似乎是路由器 (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);
    }
}

编辑

所以它似乎出于某种原因在仅 VirtualBox 主机的网络接口上发布 UDP 数据包,而不是所有机器都连接到的无线网络。只需要弄清楚如何让它不这样做...... 所以在答案中添加了解决方案......

【问题讨论】:

  • 您的网络上是 IPv4 还是 IPv6?

标签: c# udp multicast


【解决方案1】:

所以问题是因为我有超过 1 个活动网络连接,它选择了一个并使用它,这导致 UDP 数据包在客户端正在侦听的不同网络连接上发送出去。当我安装了 Virtual Box 时,它已经安装并激活了 VirtualBox Host-only 网络适配器,因此可以支持仅主机网络连接。当我将 VirtualBox 切换到仅主机模式时,开始接收数据包。禁用 VirtualBox 适配器并切换回桥接连接也有效。

【讨论】:

  • 如果您不指定,操作系统会选择一个默认接口来发送数据包。对于单播数据包,将使用路由度量来选择接口(即,它将尝试选择离目的地“最近”的接口)。对于多播,可能有一种方法可以配置哪个接口是默认的,但通常您的程序应该自己(或通过用户配置)确定要使用哪个接口,并通过适当的 API 指定这一点(我不在 C# 中编程,所以我不能更具体)
  • 我在这方面花了很多时间,特别是使用 VirtualBox 来测试接收多播数据包。我听从了您的评论,并在我的主机计算机上禁用了 VirtualBox 网络适配器——一旦我这样做了,客户端软件就开始接收 UDP 数据包。
【解决方案2】:

如果您有多个接口,正确的答案是听取所有接口,如果您没有正确的定义,则不要尝试选择一个。

以下是我实现 UDP 发现服务的方法。最初它坏了,因为我的 Virtual Box 接口挡住了路,吞下了随机 IP 子网 (192.168.56.x) 上的 UDP 广播,而不是我的实际以太网连接 (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;

    }

【讨论】:

    【解决方案3】:

    我会试试Wireshark。

    【讨论】:

    • 是的,我已经开始安装它了。我也希望有其他选择。哦,我们会看到的,我想......
    • 这确定了问题,数据进入了错误的网络接口。
    【解决方案4】:

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

    首先是:您确定多播是最好的方法吗?我认为广播会更好地为您服务。

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

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

    编辑:

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

    【讨论】:

    • 问题是数据进入了错误的接口。不知道我怎样才能让它去正确的...
    【解决方案5】:

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

    【讨论】:

      猜你喜欢
      • 2014-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-11
      • 1970-01-01
      • 2021-05-19
      • 2020-01-25
      • 1970-01-01
      相关资源
      最近更新 更多