什么可能导致 UDP 数据包计时不一致?

Posted

技术标签:

【中文标题】什么可能导致 UDP 数据包计时不一致?【英文标题】:What could be causing UDP Packet timings to be inconsistent? 【发布时间】:2022-01-05 12:10:55 【问题描述】:

我一直在研究一个读取鼠标输入的项目,然后通过 UDP 将其发送到另一台计算机,然后重新创建鼠标输入。我在 UDP 数据包计时方面遇到了奇怪的问题,仅在我的一台计算机上,似乎 UDP 数据包可能被组合在一起?我已经设置了一些简单的代码,它每 10 毫秒发送一个大约 12 个字节的 udp 数据包

while(true)

    Packet p = new Packet(Packet.Type.MOUSE_MOVE, id++, (float)50, (float)50);
    Send(p);
    System.Threading.Thread.Sleep(10);

但是,接收这些数据包的服务器并没有像我预期的那样每 10 毫秒接收一个数据包。

相反,测量“自上次数据包以来的时间”会显示以下时间:

[1440] [6.0834ms]   MOUSE_MOVE: 50, 50
[1441] [8.4989ms]   MOUSE_MOVE: 50, 50
[1442] [9.7771ms]   MOUSE_MOVE: 50, 50
[1443] [59.8888ms]  MOUSE_MOVE: 50, 50
[1444] [0ms]        MOUSE_MOVE: 50, 50
[1445] [0.4995ms]   MOUSE_MOVE: 50, 50
[1446] [0.4985ms]   MOUSE_MOVE: 50, 50
[1447] [0ms]        MOUSE_MOVE: 50, 50
[1448] [0ms]        MOUSE_MOVE: 50, 50
[1449] [6.0016ms]   MOUSE_MOVE: 50, 50
[1450] [6.001ms]    MOUSE_MOVE: 50, 50
[1451] [10.0007ms]  MOUSE_MOVE: 50, 50
[1452] [64.4198ms]  MOUSE_MOVE: 50, 50
[1453] [0ms]        MOUSE_MOVE: 50, 50
[1454] [0.5021ms]   MOUSE_MOVE: 50, 50
[1455] [0ms]        MOUSE_MOVE: 50, 50
[1456] [0.5017ms]   MOUSE_MOVE: 50, 50
[1457] [0ms]        MOUSE_MOVE: 50, 50
[1458] [5.4997ms]   MOUSE_MOVE: 50, 50
[1459] [7.4957ms]   MOUSE_MOVE: 50, 50
[1460] [10.5004ms]  MOUSE_MOVE: 50, 50
[1461] [66.7724ms]  MOUSE_MOVE: 50, 50
[1462] [0ms]        MOUSE_MOVE: 50, 50
[1463] [1.5007ms]   MOUSE_MOVE: 50, 50
[1464] [0ms]        MOUSE_MOVE: 50, 50
[1465] [0ms]        MOUSE_MOVE: 50, 50

显然,我的代码之外一定有某些东西,或者 UdpClient 中的某些设置正在改变幕后的时间,否则我看不出我的服务器如何可能以

另一件值得注意的事情是,有时“数据包之间的时间”测量值会达到 60 毫秒左右。我测量了这种情况发生的频率,它似乎每 100 毫秒就会出现一次峰值(给或需要 1 或 2 毫秒)

基于此,我认为必须在发送数据包之前将它们缓冲或组合在一起,可能会在 100 毫秒内收集所有数据包,然后一次性发送所有数据包。

还有一件事,我只在一台测试计算机上体验过这种类型的分组,这让我相信它可能是操作系统或驱动程序问题。该问题仅发生在 Microsoft Surface Go 上,因此它可能与它是一款动力不足的设备有关。任何帮助将不胜感激。

客户端是这样创建的:

var ip = new IPAddress(new byte[]  192, 168, 178, 63 );
endPoint = new IPEndPoint(ip, Common.Constants.SERVER_PORT);
client = new UdpClient();
client.Connect(endPoint);

和发送功能:

private void Send(Packet p)

    var data = p.ToByteArray();
    client.Send(data, data.Length);

接收线程:

    private static void ServerThread()
    
        while (running)
        
            var clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
            var clientData = server.Receive(ref clientEndPoint);

            if (clientData.Length > 0)
            

                Packet p = new Packet(clientData);

                var time = DateTime.Now - last;

                Console.WriteLine($"[p.id] [time.TotalMillisecondsms] p.type: p.x, p.y");

                last = DateTime.Now;

                if (p.type == Packet.Type.MOUSE_MOVE)
                
                    SetCursorPos((int)p.x, (int)p.y);
                
            
        
    

【问题讨论】:

发生这种情况的原因有很多。无论您做什么,UDP 数据包都可以并且将会被打包在一起。但是有一些套接字选项可以减轻一些违规行为并更快地发送。但是您需要显示显示套接字是如何创建的代码。最好也显示Send 的代码。还有你的recv 代码。 另外,仅仅因为您调用 Sleep(10) 并不意味着您将在 10 毫秒后准确地醒来。无论如何,您必须准备好在发送端和接收端处理代码中的抖动——尤其是当您每秒发送 100 个数据包时。另一个问题:除了最后一个数据包,你为什么还要关心鼠标的移动? @selbie 我添加了您要求的额外信息,但我假设调用 Sleep(10) 至少会休眠超过 1 毫秒。至于为什么我需要对每个数据包进行一致的鼠标移动,是因为该项目是专门针对数字绘图/雕刻的远程工作,因此笔画的形状至关重要。您是否有任何您提到的套接字选项的示例? 【参考方案1】:

我认为问题出在这一行:

System.Threading.Thread.Sleep(10);

系统的计时器不是很准确。 您可以找到更准确的计时器来执行此操作。

【讨论】:

【参考方案2】:

我相信我可能找到了解决方案,通过禁用“Microsoft Virtual WiFi Adapter”,数据包时序似乎变得更加一致。

在提升的命令提示符下:

netsh wlan stop hostednetwork

netsh wlan set hostednetwork mode=disallow

【讨论】:

以上是关于什么可能导致 UDP 数据包计时不一致?的主要内容,如果未能解决你的问题,请参考以下文章

使用 esp32 接入点流式传输 UDP 数据包会导致大量数据包丢失

Java UDP 客户端不接收数据包

UDP协议是啥

防火墙为何不允许接收UDP协议数据包

关于UDP的问题:包含多条消息和跨越的数据包

在一个线程中定期发送许多 UDP 数据报有时会导致微包突发