为什么发送连续的UDP消息导致消息迟到?

时间:2018-01-25 00:48:41

标签: python c linux multithreading sockets

我在Windows 7中编写了一个服务器python脚本,将以太网UDP数据包发送到运行C客户端接收程序的UNIX系统,该程序将消息发送回服务器。但是,有时(并不总是)python发送到的最后一个端口(始终是最后一个端口)中的消息将一直到达,直到发送下一批4条消息。这导致最后一个端口收到的消息的时间与发送时不一致,并且我不能在同一端口上重新连接两条消息

我已经能够在Wireshark中通过查找两个同时到达的消息来验证这一点,因为未收到的消息是用另一个消息处理的。我还在recv()函数之后检查了时间,它显示了一个很长的延迟,然后是一个短暂的延迟,因为它基本上收到了两个数据包。

我已尝试解决此问题,但帮我解释了问题或如何解决问题:我可以在每个sendto()之间添加延迟,我会成功发送和接收所有正确时间的消息,但我希望测试按照我在下面写的方式工作;我已经增加了接收线程的优先级,认为我的以太网接收没有收到信号来接收包或者某个进程花了太长时间,但这没有工作,20ms应该比处理数据所必需的;我已经删除了端口C和D,然后端口B丢失了消息(只有一个端口不会导致问题),我认为减少端口数量会改善时序;在PORTD之后立即发送到虚拟PORTE让我以正确的时序接收所有消息(我假设问题转移到PORTE);我还在UNIX环境和C代码中复制了python脚本并且遇到了同样的问题,指出了接收问题;我还设置了我的recv功能,每1ms超时一次,希望它能以某种方式恢复,即使时间稍微偏离,但我仍然看到消息背靠背。我还检查过没有删除UDP数据包,并且缓冲区足够大以容纳这4条消息。任何新想法都会有所帮助。

这是代码的核心,python脚本将发送4个数据包。一个20字节的消息到C中相应的等待线程,延迟20ms

python代码的表示看起来像

msg_cnt = 5000 
while cnt < msg_cnt:
   UDPsocket.sendto(data, (IP, PORTA))
   UDPsocket.sendto(data, (IP, PORTB))
   UDPsocket.sendto(data, (IP, PORTC))
   UDPsocket.sendto(data, (IP, PORTD))

   time.sleep(.02)
   cnt++

C代码有4个线程等待在相应的端口上接收。基本上每个线程都应接收其数据包,对其进行处理,然后发送回服务器。在下一组消息到达之前,此过程应该少于20毫秒

void * receiveEthernetThread(){
     uint8_t ethRxBuff[1024];
     if((byteCnt = recv(socketForPort, ethRxBuff, 1024, 0)) < 0){
         perror("recv")
     }else{
        //Process Data, cannot have back to back messages on the same port
        //Send back to the server
     }
}

2 个答案:

答案 0 :(得分:1)

我发现了一段时间后我错过了消息并想回答我的问题的原因。我在Zynq-7000上运行该程序并没有意识到这将是一个问题。

在Xilinx Zynq-7000-TRM中,有一个已知问题描述:

&#34;最后一帧可能会卡在RX FIFO中,而软件无法将最后一帧从那里取出。 GEM仅在接收到另一帧时才启动描述符请求。因此,当一个帧在FIFO中并且描述符仅在以后可用并且没有新帧到达时,就无法获得该帧或者甚至不知道它是否存在。

在典型的操作条件下不会发生此问题。典型的操作条件是系统始终具有传入的以太网帧。当MAC停止接收以太网帧时,会出现上述问题。

解决方法:除了确保以太网帧的连续流动外,软件中没有解决方法。&#34;

基本上是通过连续传入以太网流量来修复,遗憾的是遗漏了这些关键信息。

答案 1 :(得分:0)

  

这会导致收到最后一个端口的消息的时间   它发送时不正确,我不能回复两条消息   回到同一个港口。

简短的解释是您正在使用UDP,并且该协议不保证交付或订单。

除此之外,你所描述的最绝对听起来像是一个缓冲问题。不幸的是,没有真正的方法可以“刷新”套接字。

您需要使用能够保证所需(TCP)的协议,或者在UDP之上实现您的需求。

我相信你真正的问题是如何在服务器端解析数据。如果您的应用程序完全依赖于来自网络的四个独立数据包的20毫秒间隔,那只是在寻找麻烦。如果可能的话,我会解决这个问题而不是尝试修复(正常)套接字缓冲问题。

一个hacky解决方案,因为我喜欢hacky的东西:

在服务器上设置第五个套接字。发送四个时间敏感的数据包后,向第五个端口发送“足够”的数据包,以强制执行任何剩余的时间敏感数据包。什么是“足够”的数据包取决于你。您可以发送一个静态号码,假设它可以正常工作,或让第五个端口在它开始重新开始时向您发送一条消息。