从套接字部分读取

10
我正在进行一个小测试程序,它在客户端和服务器之间发送大量的UDP数据包(ping/pong测试)。每次运行时,数据包的大小是固定的(最后一次运行是UDP数据包的最大允许大小)。我用随机数据填充数据包,除了每个数据包的开头包含数据包编号。所以我只关心在客户端是否收到了所有的数据包。
我使用sendto()和recvfrom()函数,只读取了packet_number的大小(在这种情况下是一个int)。其他数据会发生什么?它们会被丢弃吗?还是新到达的数据包会附加到这个“旧”数据上?
(使用Linux系统)
3个回答

16

每次从UDP套接字读取时,无论您的用户空间缓冲区大小是多少,都会从内核套接字接收缓冲区中出列一个完整的数据报。也就是说:

  • 如果您的缓冲区比下一个待处理数据报大,则读取的数据量少于您的缓冲区大小。
  • 如果您的缓冲区较小,则将读取您的缓冲区大小,并丢弃其余数据。
  • 您可以在flags中设置MSG_TRUNC选项,这样recv(2)将返回整个数据报长度,而不仅仅是您读入用户空间缓冲区的部分。

希望这可以帮到您。


5

回答你的第一个问题,数据会被丢弃吗? 是的。当你的数据包大于路径MTU时,IP和ARP协议就会发挥作用。路径MTU是客户端和服务器之间路径的最大传输单元。假设你的网卡是标准以太网卡,那么你的最大MTU为1500。现在,假设你的客户端和服务器之间的整个路径MTU都是1500。在这种情况下,如果你发送任何大于1472字节(1500 -(20字节IP头)-(8字节UDP头))的数据包,则会发生IP分段。然后,IP层将把数据包切成片段以满足以太网链路的MTU。现在,在发送任何数据之前,需要解析目标的MAC地址。因此,突然之间,ARP协议将接收到多个IP分段请求相同IP到MAC地址的解析。然后,ARP将为第一个接收的数据包启动ARP请求并等待ARP响应。在等待期间,ARP将丢弃所有制作相同ARP请求的分段,并仅排队最新到达的分段。因此,如果你发送大于1472字节的数据包,并且你的ARP缓存为空,则不要指望在另一端接收整个数据包。

新到达的数据包是否会被附加到现有数据上? 不会,它不会被附加。UDP是一种带有严格消息边界的数据报协议。因此,每个到达的数据包都被视为完整的自包含数据报;数据不会被附加。


1
这个问题与MTU无关,完全是关于套接字API的(以及进行短读取的影响)。 - caf
@caf - 如果您重新阅读问题,它指出:(最后一次运行是UDP数据包的最大允许大小),这意味着长度设置为UDP的“理论”最大数据包大小。请阅读Richard Stevens的书《TCP/IP详解:卷1》第11.9节-UDP和ARP之间的交互。您会明白我为什么提到MTU和ARP。 - WindsurferOak
1
为了纪录:上面的回答有点混淆。ARP不涉及IP分段。 ARP用于查找下一跳的MAC地址(如果它是单播数据报)。但ARP是完全独立的协议。在目标MAC地址未知之前,将不会发送任何IP数据报(先进行ARP,然后进行IP)。如果ARP花费太长时间,那么它可能会被丢弃,因为UDP没有可靠性。但是,整个事情都会被丢弃。接收器可能无法收到某些分段,这将导致它也放弃整个数据报,但这不是ARP的结果。 - Gil Hamilton
数据会被丢弃吗?是的,但不是因为这里所述的任何原因。ARP在丢弃数据包方面没有任何作用。你对W.R Stevens的阅读完全错误。新到达的数据包会被追加吗?是的,作为IP层的基本功能,会被追加。回答完全错误。 - undefined

3

我没有测试过这个功能,但从man手册的解释来看,数据包将被丢弃。这似乎是合理的,否则就无法检测到下一个数据包的开始。

有两种方法可以检测截断:

使用 MSG_TRUNC 标志。如果数据包大小超出了提供的缓冲区大小,recvfrom 将返回真实的数据包大小。因此,您只需检查返回值是否大于您作为参数提供的 len 即可。

使用 recvmsg 并检查返回的结构中是否存在 MSG_TRUNC 标志。

为避免截断,请使用 64k 缓冲区。UDP 数据包不能大于此大小(协议中的 16 位长度字段)。


它们实际上不能超过65507,因为IP头部的最小大小为20字节,UDP头部为8字节。 - undefined

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