我使用sendto()和recvfrom()函数,只读取了packet_number的大小(在这种情况下是一个int)。其他数据会发生什么?它们会被丢弃吗?还是新到达的数据包会附加到这个“旧”数据上?
(使用Linux系统)
每次从UDP套接字读取时,无论您的用户空间缓冲区大小是多少,都会从内核套接字接收缓冲区中出列一个完整的数据报。也就是说:
flags
中设置MSG_TRUNC
选项,这样recv(2)
将返回整个数据报长度,而不仅仅是您读入用户空间缓冲区的部分。希望这可以帮到您。
回答你的第一个问题,数据会被丢弃吗? 是的。当你的数据包大于路径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是一种带有严格消息边界的数据报协议。因此,每个到达的数据包都被视为完整的自包含数据报;数据不会被附加。
我没有测试过这个功能,但从man手册的解释来看,数据包将被丢弃。这似乎是合理的,否则就无法检测到下一个数据包的开始。
有两种方法可以检测截断:
使用 MSG_TRUNC
标志。如果数据包大小超出了提供的缓冲区大小,recvfrom
将返回真实的数据包大小。因此,您只需检查返回值是否大于您作为参数提供的 len
即可。
使用 recvmsg
并检查返回的结构中是否存在 MSG_TRUNC
标志。
为避免截断,请使用 64k 缓冲区。UDP 数据包不能大于此大小(协议中的 16 位长度字段)。