一个UDP数据包在套接字中停留多久?

19
如果数据已发送到客户端但客户端正忙于执行其他任务,那么使用recvfrom()读取数据的时间有多长?
此外,如果在读取第一个数据包之前发送了第二个数据包,那么第一个数据包是否丢失,下一个数据包是否等待被读取?
(Windows-UDP)

1
一旦数据实际到达目标机器,我会认为它可能会被类似于TCP流量的方式处理 - 数据报将在某个缓冲区中等待,以到达数据报的顺序,直到被读取。(如果缓冲区已满,操作系统可能会完全丢弃该数据包。) - millimoose
3
如果你担心数据包的丢失和顺序问题,为什么要使用UDP?如果你发现自己在问这样的问题,那么这非常明显地表明你应该使用TCP。 - Remus Rusanu
为什么不使用TCP呢?因为一些协议(例如DNS)需要UDP支持。 - bluejekyll
我在一秒钟后读取接收缓冲区,但什么也没有。如果我使用非阻塞的rcvfrom调用连续读取它,我可以读取数据包。为什么会这样? - Darkgaze
3个回答

24
如果数据已发送到客户端,但客户端正在执行其他任务,使用recvfrom()读取数据的可用时间是多久? 永远可用,或者根本不可用,或者直到您关闭套接字或读取至少一个字节为止。
其原因在于: UDP传递数据报,要么成功,要么失败。这听起来像胡说八道,但确实如此。
单个UDP数据报与一个或多个“片段”相关联,这些片段是IP数据包(进一步封装在某种“在线”协议中,但这并不重要)。网络堆栈收集数据报的所有片段。如果任何片段上的校验和不好或任何其他使网络堆栈不满意的事情,完整的数据报将被丢弃,您什至不会得到错误消息,您根本不知道发生了任何事情。
如果一切顺利,完整的数据报将放入接收缓冲区。从未有过不足一条完整数据报,也从未有过超过一条完整数据报。如果稍后尝试recvfrom,那就是你会得到的。
接收缓冲区显然必须足够大以容纳至少一个最大大小数据报(65535字节),但由于通常数据报不会达到最大大小,而是低于1280字节(或1500字节),因此它通常可以容纳相当多的数据报(在大多数平台上,缓冲区默认配置为约128-256k)。如果缓冲区中剩余的空间不足,则数据报将被丢弃,您什至什么都得不到(好吧,您仍然会得到已经在缓冲区中的数据报)。同样,您甚至不知道发生了任何事情。每次调用recvfrom,都会从缓冲区中删除一个完整数据报(这是重要的细节!),并获取最多请求的字节数。这意味着,如果你天真地尝试读取几个字节,然后再读取几个字节,它就不起作用了。第一次读取将丢弃数据报的其余部分,并且随后的读取将读取一些未来数据报的第一批字节(并可能阻塞)!
这与TCP的工作方式非常不同。在这里,您实际上可以分几次读取几个字节,并且它会正常工作,因为网络层模拟了数据流。您不需要关心它的工作原理,因为网络堆栈确保它正常工作。
此外,如果在读取第一个请求之前发送第二个数据包会发生什么情况?第一个数据包丢失,下一个数据包还在等待被读取吗?
你可能是想说“接收”而不是“发送”。发送和接收有不同的缓冲区,所以这一点根本不重要。关于在一个数据包仍在缓冲区中时接收另一个数据包的情况,请参见上面的解释。如果缓冲区可以容纳第二个数据报,它将存储它,否则它将静默地消失。这不会影响已经在缓冲区中的任何数据报。

1
“你根本不知道发生了什么”这句话并不完全正确,在某些堆栈中,有关丢弃的数据包统计是存在的,原因可能是丢失的片段、无效的校验和、缓冲区空间不足等等。但是确实如此,使用通常的机制你永远不会收到部分数据包。 - Ben Voigt
1
但这并不是真的。我向套接字发送了数据包,然后在一秒钟后读取了套接字,但什么也没有。如果我使用非阻塞调用在循环中主动读取(rcvfrom),我就能收到数据包。为什么会发生这种情况呢? - Darkgaze

9

通常情况下,数据会被缓冲直到读取。我想如果你等待足够长的时间,驱动程序完全耗尽空间,它将不得不做一些事情,但是假设您的代码运行得比较合理,那就不应该成为问题。

一个典型的网络驱动程序将能够缓冲多个数据包而不会丢失任何一个。


5
主要会填满套接字缓冲区,而不仅仅是驱动程序。它会一直保留在套接字缓冲区中,直到您读取它或进程退出。一旦套接字缓冲区已满,新到达的数据包将被丢弃。 - nos

7
如果数据已发送到客户端,但客户端正在执行其他操作,使用recvfrom()读取数据的可用时间取决于操作系统,在Windows中,我相信每个UDP套接字的默认值是8012,可以使用setsockopt() Winsock Documentation来提高它。因此,只要缓冲区不满,数据将保留在那里,直到套接字关闭或被读取。

如果第一个数据包未被读取,就有第二个数据包被发送,它们将存储在缓冲区中,如果没有足够的空间,它们中的一个将被丢弃,最新的那一个会被保留。

1
数据一旦被接受,就会永久保存;但如果已经缓冲了太多旧数据,则新数据将被丢弃。 - R.. GitHub STOP HELPING ICE
除了我从recv_from接收的源之外,其他源的数据包会发生什么?它们只是会淹没操作系统缓冲区吗? - Aleš Koblížek
@AlešKoblížek:recvfrom没有指定从哪个发送者接收数据,它让你的程序找出发送者的地址(地址参数是输出而不是输入)。因此,不存在“除了我使用recvfrom之外的其他来源”。recvfrom从所有来源接收数据。 - Ben Voigt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接