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

时间:2016-01-11 20:27:10

标签: c# sockets networking network-programming udp

美好的一天

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

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

以下是我测试返回/接收哪些数据包的测试。发送了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提出他的建议

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

我禁用了我的卡巴斯基防火墙,然后又回到了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

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

1 个答案:

答案 0 :(得分:3)

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

  • 2000字节大于典型的LAN MTU 1500(标题较少)。这意味着数据报将被分割。如果任何片段丢失,整个数据报都会丢失,如果某些防火墙以某种模式到达,它们将阻止碎片。
  • UDP本身没有流量控制。如果发送的数据过多,则数据包将被丢弃。听起来你一次只发送一些数据报,但检查你的UDP发送和接收缓冲区。如果其中任何一个只能容纳一个或两个数据报,那么其余数据报可能会丢弃。
  • 防火墙有时会奇怪地对待UDP。 DoS预防,深度数据包检测,隧道阻塞以及一堆安全声音流行语意味着防火墙会对数据报的目的进行疯狂的猜测。如果防火墙猜错了,可能会删除一些数据报。
  • 看起来你将TTL设置为1.从理论上讲,这对于LAN来说是正确的。但是如果本地路由有点过时,可能会导致某些数据包被丢弃。

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

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