从套接字部分读取
我有一个小测试程序,它在客户端->服务器->客户端之间发送大量 udp 数据包(ping/pong 测试)。每次运行时数据包的大小都是固定的(最后一次运行是 udp 数据包的最大允许大小)我用随机数据填充数据包,除了包含数据包编号的每个数据包的开头。所以我只想看看我是否收到客户端返回的所有数据包。
我正在使用 sendto()
和 recvfrom()
并且我只读取 sizeof(packet_number) (在本例中是一个 int)。其余数据会怎样?它最终会进入仙境吗(被丢弃)?或者到达的新数据包是否会附加到这个“旧”数据中?
(使用Linux)
I'm having a little test program that sends a lot of udp packets between client->server->client (ping/pong test). The packets are fixed size on each run (last run is max allowable size of udp packet) I'm filling the packets with random data except for the beginning of each packet that contains the packet number. So I'm only interested to see if I receive all the packets back at the client.
I'm using sendto()
and recvfrom()
and I only read the sizeof(packet_number) (which in this case is an int). What happens to the rest of the data? Does it end up in fairyland (gets discarded)? Or does the new packet that arrives gets appended to this "old" data?
(using linux)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
无论您的用户态缓冲区大小是多少,每次从 UDP 套接字读取都会从内核套接字接收缓冲区中取出整个数据报。也就是说:
flags
中设置MSG_TRUNC
选项,因此recv(2)
将返回整个数据报长度,而不仅仅是您读入用户区缓冲区的部分。希望这有帮助。
Each read from UDP socket de-queues one whole datagram off kernel socket receive buffer no matter what's your userland buffer size. That is:
MSG_TRUNC
option in theflags
, sorecv(2)
will return the whole datagram length, not just the part you read into your userland buffer.Hope this helps.
回答你的第一个问题,数据会被丢弃吗?
是的,确实如此。知识产权与当数据包大于路径 MTU 时,ARP 协议就会发挥作用。路径 MTU 是客户端和服务器之间路径的最大传输单元。假设您的网卡是标准以太网卡,则最大 MTU 为 1500。现在,假设客户端和服务器之间的整个路径 MTU 为 1500。在这种情况下,如果您发送任何大于 1472 字节的数据包(1500 - (20 字节 ip 标头) - (8 字节 UDP 标头)) 那么就会发生 IP 碎片。接下来,IP 层会将数据包切成碎片以满足以太网链路的 MTU。现在,在发送任何数据之前,需要解析目的地的 MAC 地址。因此突然间,ARP 协议将收到多个请求相同 IP 到 MAC 地址解析的 IP 片段。然后,ARP 将对第一个收到的数据包发起 ARP 请求,并等待 ARP 响应。在等待期间,ARP 将丢弃发出相同 ARP 请求的所有分片,并仅对最新到达的分片进行排队。因此,如果您发送的数据包大于 1472 字节,并且您的 ARP 缓存为空,则不要指望在另一端收到整个数据包。
新到达的数据包是否会附加到
不,它不会被附加。 UDP 是一种具有严格消息边界的数据报协议。因此,每个到达的数据包都被视为一个完整的自包含数据报;数据不会被附加。
To answer your first question, does the data get discarded?
Yes it does. The IP & ARP protocols come into play when your packet is larger than the Path MTU. The Path MTU is the maximum transmission unit of the path between your client and server. Assuming that your NIC card is a standard ethernet card, then your maximum MTU is 1500. Now, lets assume that the whole Path MTU between your client and server is 1500. In this scenario, if you send any packet that is greater than 1472 bytes (1500 - (20 byte ip header) - (8 byte UDP header)) then IP fragmentation will occur. What will then happen is that the IP layer will chop the packet into fragments to meet the MTU of the ethernet link. Now, before any data can be sent, the MAC address of the destination needs to be resolved. So all of a sudden, the ARP protocol will receive multiple IP fragments requesting the same IP to MAC address resolution. What will then happen is that ARP will initiate an ARP request for the first received packet and wait for the ARP response. While waiting, ARP will discard all of the fragments making the same ARP request and queue only the latest arrived fragment. Therefore, if you send a packet greater than 1472 bytes, don't expect to receive the whole packet on the other end if your ARP cache is empty.
Does the newly arrived packet get appended to
No, it doesn't get appended. UDP is a datagram protocol with strict message boundaries. Therefore, each arriving packet is considered as a complete self-contained datagram; the data will not get appended.
我还没有对此进行测试,但从我对手册页的解释来看,它将永远被丢弃。这似乎是合理的,因为否则将无法检测下一个数据包的开始。
有两种方法可以检测截断:
使用
MSG_TRUNC
标志。然后,recvfrom 将返回包的真实大小,即使它不适合提供的缓冲区。因此,您可以简单地检查返回值是否大于您作为参数给出的 len 。使用
recvmsg
并检查返回的结构中是否有MSG_TRUNC
标志。为避免截断,请使用 64k 缓冲区。 UDP 包不能大于该值(协议中的 16 位长度字段)。
I haven't tested this, but from my interpretation of the man page, it will always be discarded. This seems reasonable since otherwise there would be no way to detect the beginning of the next packet.
There are two ways to detect truncation:
Use the
MSG_TRUNC
flag.recvfrom
will then return the true size of the package even if it didn't fit the provided buffer. So you can simply check if the return value is larger then thelen
you gave as an argument.Use
recvmsg
and check the returned structure for theMSG_TRUNC
flag.To avoid truncation, use a 64k buffer. UDP packages can't be bigger than that (16 bit length field in the protocol).