C# - 可以发送 5 个多播 UDP 数据包导致 3 个或更多丢失

C# - Could sending 5 Multicast UDP packets result in 3 or more being lost

大家好

通过 LAN 发送多播数据包是否可能导致部分或至少 50% 的数据包丢失。

我的应用程序使用多播数据包,发送这些数据包时,有时我只收到 1 个,其他时候收到 2 个。只有 2 次我收到了我发送的所有数据包。

这是我为查看哪些数据包 returned/received 所做的测试。发送了 5 个数据包,并非全部返回(F - 发送数据包序列中的最后一个数据包)

2000 个随机字符用于这些测试。

12345 14F

12345 134F

12345 1F

12345 1

12345 1

12345 1F

12345 134F

我总是至少收到 1 包。我理解Multicast = UDP,但是丢这么多包好像不太正常

正在发送多播数据包:

        Socket _listener_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        foreach (IPAddress localIP in Dns.GetHostAddresses(Dns.GetHostName()).Where(i => i.AddressFamily == AddressFamily.InterNetwork))
        {                
            _listener_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(_MultiIP, localIP));
            _listener_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 1);
            _listener_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            _listener_socket.MulticastLoopback = true;
            _listener_socket.Connect(new IPEndPoint(_MultiIP, _PORT));
            int count = MSGS_TO_SEND.Count;
            while (count > 0)
            {                    
                count--;
                byte[] temp = (byte[])(MSGS_TO_SEND.Dequeue());
                _listener_socket.Send(temp, _BYTE_BUFFER_SIZE, SocketFlags.None);
                MSGS_TO_SEND.Enqueue(temp);
            }
        }
        _listener_socket.Close();

并收到:

        Socket _sender_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        IPEndPoint ipep = new IPEndPoint(IPAddress.Any, _PORT);
        _sender_socket.Bind(ipep);
        IPAddress localip = _MultiIP;
        _sender_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(localip, IPAddress.Any));
        Q_RECIEVE = new Queue<char[]>();
        while (_sender_socket.IsBound && !bStop)
        {
            byte[] b = new byte[_BYTE_BUFFER_SIZE];
            _sender_socket.Receive(b);
            char[] chars = new char[_BYTE_BUFFER_SIZE];
            System.Buffer.BlockCopy(b, 0, chars, 0, b.Length);
            Q_RECIEVE.Enqueue(chars);
        }

更新

一些有趣的结果 - Kudo 对 Seth 的建议

测试防火墙建议后,我得到了一些改善,但仍然有丢包:

我禁用了我的 Kaspersky 防火墙,默认回到 Windows 10 Defender 防火墙:

12345 234F

12345 234F

12345 1234F

12345 1F

12345 14F

12345 234F

12345 1

12345 1

12345 234F

禁用卡巴斯基防火墙后,我将 byte[] 大小从 1024 更改为 512,因此每个数据包仅发送 256 个字符(线程休眠时间为 20ms),结果显着改善:

123456789 2345678F

123456789 2345678F

123456789 2345678F

123456789 2345678F

123456789 2345678F

只有我的第一个数据包被丢弃,但这是一个很大的进步!

是的,任何时候发送 UDP 都会有多种因素导致数据包丢失,即使在 LAN 上也是如此。以下是一些似乎相关的内容:

  • 2000 字节大于典型的 LAN MTU 1500(小于 headers)。这意味着数据报将被分段。如果任何一个片段丢失,整个数据报都会丢失,如果片段以特定模式到达,一些防火墙会阻止片段。
  • UDP本身没有流量控制。如果发送的数据太多、太快,数据包就会被丢弃。听起来您一次只发送几个数据报,但请检查您的 UDP 发送和接收缓冲区。如果其中一个仅大到足以容纳一个或两个数据报,则其余的可能会被丢弃。
  • 防火墙有时会以奇怪的方式对待 UDP。 DoS 预防、深度数据包检查、隧道阻塞和一堆听起来很安全的流行语意味着防火墙对数据报的目的进行了疯狂的猜测。如果防火墙猜测不正确,您的某些数据报可能会被丢弃。
  • 您似乎将 TTL 设置为 1。理论上,这对于 LAN 是正确的。但是如果本地路由有点偏离,那可能会导致一些数据包被丢弃。

因此,将您的负载减少到 1400 字节,确保您的 UDP 发送和接收缓冲区至少为 64 KB(最好是 1 兆字节,没有理由吝啬),禁用任何防火墙,并使用更大的 TTL 进行测试.

如果其中任何一项解决了问题,您可以深入了解确切原因。