我有一个简单的客户端/服务器设置。服务器在C中,查询服务器的客户端是Java。
我的问题是,当我通过连接发送带宽密集型数据时,例如视频帧,它会丢弃一半的数据包。我确保在服务器端正确分割udp数据包(udp的最大有效负载长度为2 ^ 16)。我验证了服务器正在发送数据包(printf是sendto()的结果)。但是java似乎没有获得一半的数据。
此外,当我切换到TCP时,所有视频帧都会通过,但延迟会开始增加,在运行几秒后会增加几秒钟的延迟。
我有什么明显的遗失吗?我似乎无法弄清楚这一点。
答案 0 :(得分:9)
获取Wireshark之类的网络工具,以便了解网络上发生的情况。
UDP不进行重传尝试,因此如果某个数据包被丢弃,则由程序来处理丢失。 TCP将努力将所有数据包按顺序传送到程序,丢弃重复并自行请求丢失数据包。如果你看到高延迟,我敢打赌你会看到很多TCP丢包,这将显示为来自服务器的重传。如果您没有看到TCP重新传输,可能客户端没有足够快地处理数据以便跟上。
答案 1 :(得分:3)
任何基于UDP的应用程序协议都不可避免地容易受到数据包丢失,重新排序和(在某些情况下)重复的影响。 UDP中的“U”可以表示“不可靠”,如不可靠数据报协议中所示。 (好吧,它确实代表“用户”......但它肯定是记住UDP特性的好方法。)
通常会发生UDP数据包丢失,因为您的流量超过了服务器和客户端之间的一个或多个“跃点”的缓冲容量。发生这种情况时,数据包将被丢弃......由于您使用的是UDP,因此没有传输协议级别的通知。
如果在应用程序中使用UDP,则应用程序需要考虑UDP的不可靠性,实现自己的机制来处理丢弃和无序数据包以及执行自己的流控制。 (一个突发出UDP数据包而不考虑这可能对已经过载的网络造成影响的应用程序是坏网络公民。)
(在TCP情况下,数据包可能也被丢弃,但TCP正在检测并重新发送丢弃的数据包,并且TCP流量控制机制正在开始降低数据传输速率。最终结果是“延迟”。)
编辑 - 根据OP的评论,他的问题的原因是客户端没有“监听”一段时间,导致数据包(大概)被客户端的OS删除。解决这个问题的方法是:
使用只读取数据包并将其排队等待处理的专用Java线程,
增加套接字的内核数据包队列的大小。
但即使你采取这些措施,你仍然可以丢弃数据包。例如,如果机器过载,应用程序可能无法经常执行时间片,以便在内核必须丢弃它们之前读取和排队所有数据包。
编辑2 - 关于UDP是否容易出现重复,存在一些争议。毫无疑问,UDP没有固有的重复检测或预防。但是,作为互联网的IP分组路由结构也不太可能自发地复制分组。因此,如果确实发生重复,则可能会发生重复,因为发送方已决定重新发送UDP数据包。因此,在我看来,虽然UDP容易出现重复问题,但它不会导致它们本身 ......除非OS协议栈或IP结构中存在错误。
答案 2 :(得分:2)
虽然UDP支持最长65535字节的数据包(包括 UDP标头,这是8字节 - 但请参见注释1),但您和目标之间的基础传输不支持IP数据包那么长。例如,以太网帧的最大大小为1500字节 - 考虑到IP和UDP报头的开销,这意味着任何数据有效负载长度超过1450的UDP数据包很可能被分段为多个IP数据报。
最大大小的UDP数据包将被分段为至少45个单独的IP数据报 - 如果这些片段中的任何一个丢失,则整个UDP数据包将丢失。如果您的基础丢包率为1%,您的应用程序将看到大约36%的丢失率!
如果你想看到更少的数据包丢失,不要发送大量数据包 - 将每个数据包中的数据限制在大约1400字节(甚至自己做“路径MTU发现”,以确定你可以安全发送的最大数量没有碎片)。
答案 3 :(得分:0)
问题可能是你的传输缓冲区被UDPSocket填满了。仅发送UDPSocket.getSendBufferSize()
指示的一次性字节数。使用setSendBufferSize(int size)
增加此值。
如果#send()用于发送 DatagramPacket大于 然后设置SO_SNDBUF 具体实现如果是数据包 发送或丢弃。
答案 4 :(得分:0)
IP 支持最多65535字节的数据包,包括 20 字节的IP数据包标头。 UDP 支持最多65507字节的数据报,以及20字节的IP标头和 8 字节的UDP标头。然而,网络MTU是实际限制,并且不要忘记它不仅包括这28个字节,还包括以太网帧头。未分段UDP的实际实际限制是所有开销减去576字节的最小MTU。