因此,在 TCP 流的情况下,需要跟踪每次recv
调用读取了多少消息。然后可以将部分读取拼凑在一起,最终可以正常接收消息。
但是对于 UDP 消息,应该如何处理部分读取(假设所有 UDP 消息都小到可以避免碎片)?由于部分消息的剩余数据似乎被丢弃,是否只是确保recvfrom
返回与已发送的缓冲区大小相同的问题?如果存在差异,则意味着它是部分且有缺陷的消息,应该跳过它。
所以从概念上讲,虽然 TCP 示例需要一个循环,但 UDP 示例只需要一个 if 语句。
这个对吗?
无法在 UDP 中进行部分读取。UDP 保证接收到的数据报与发送时一样,无论是否分段,因此必须先接收到整个数据报,然后才能读取它。
请参阅:http ://en.wikipedia.org/wiki/User_Datagram_Protocol ,您可以按照其中的参考资料获取更多官方资源。
至于读入缓冲区,您将需要一个至少与任何可能的数据报一样大小的缓冲区。或者另一种常见的方法是在数据报的开头附近包含数据报的大小,这样您就可以只读取这些字节来获取该数字,然后使用适当大小的缓冲区。
不正确。如果 recv() 返回与给定相同的长度,则消息是该长度或更大。没有办法说是哪个。正确的技术是使用比预期的最大可能数据报大一号的缓冲区。那么如果你得到那个长度,那一定是发件人的错误。
正确的。但是,只有在接收方事先知道发送方正在发送多少字节时,if 条件才会起作用。
如前所述,与这个问题密切相关的是,在将这些与数据报协议一起使用时,需要一种将适当大小(足够大)的缓冲区传递给 recv/recvmsg/recvfrom 的策略。对于 UDP,一个简单且 100% 可靠的方法是传递至少 65507 字节的缓冲区,即最大 UDP 有效负载大小。
但是,我更喜欢的一种更简洁的方法是明确询问 recv() 缓冲区需要多少字节。可以这样实现:
int buflen = recv(sockfd, NULL, 0, MSG_PEEK | MSG_TRUNC);
if (buflen < 0) {
// handle error
return;
}
uint8_t buf[buflen];
rxlen = recv(sockfd, buf, buflen, 0);
if (rxlen < 0) {
// again, handle error
return;
}
// Voila! We've received our entire datagram
// without need to know the maximum datagram
// size before runtime.