因此,在TCP流的情况下,需要跟踪每个recv
调用读取消息的数量。然后可以将部分读取拼凑在一起,最终可以接收消息。
但是对于UDP消息,应该如何处理部分读取(假设所有UDP消息都足够小以避免碎片)?由于部分消息的剩余数据似乎被丢弃,是否只需要确保recvfrom
返回与发送的缓冲区相同的大小?如果存在差异,则表示它是部分且有缺陷的消息,应该跳过它。
从概念上讲,虽然TCP示例需要一个循环,但UDP示例只需要一个if语句。
这是对的吗?
答案 0 :(得分:1)
不正确的。如果recv()返回给定的相同长度,则消息的长度或更长。没有办法告诉哪个。正确的技术是使用大于预期的最大可能数据报的缓冲区。然后,如果你得到那个长度,它一定是发送者的错误。
答案 1 :(得分:1)
无法在UDP中进行部分读取。 UDP保证收到的数据报是发送,分段或不分段,所以必须先收到整个数据报才能读取。
请参阅:http://en.wikipedia.org/wiki/User_Datagram_Protocol,您可以按照其中的参考资料获取更多官方来源。
至于读入缓冲区,您需要一个至少与任何可能数据报大小相同的缓冲区。或者另一种常见的方法是在数据报开头附近的数据报中包含大小,这样您就可以只读取那些字节来获取该数字,然后使用适当大小的缓冲区。
答案 2 :(得分:0)
正确。但是,如果条件仅在接收方事先知道发送方预先发送了多少字节的情况下才会起作用。
答案 3 :(得分:0)
正如已经提到的,与这个问题密切相关的是,需要一种将适当大小(足够大)的缓冲区传递给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.