我可以确定在使用 MSG_PEEK 成功调用 recv 后立即执行的 UDP recv 不会阻塞吗?

Can I be sure that a UDP recv executed immediately after a successfull call to recv with MSG_PEEK will not block?

假设以下代码(为了简单起见,我在这里省略了必要的错误处理):

recv(sockfd, NULL, 0, MSG_PEEK);
recv(sockfd, buff, bufflen, 0);

在那种情况下:我可以确定在第一次调用 recv 之后整个数据报已经收到,因此第二次调用 recv 不会阻塞吗?

或者如果 IP 拆分数据报,第一个 recv return 会在收到此数据报的任何部分后立即发生,第二个 recv 将阻塞直到收到整个数据报?

如果我将对 recv 的第一次调用替换为:

recv(sockfd, NULL, 0, MSG_PEEK | MSG_TRUNC);

我能否确定这只会 return 一旦收到整个数据报,否则 recv 无法可靠地 return 整个数据报的长度数据报,根据 MSG_TRUNC?

的要求

Can I be sure that after the first call to recv the whole datagram is already received and therefore the second call to to recv will not block?

UDP 套接字以整个数据报为单位运行。在数据报可用之前,第一次调用不会 return ,除非它 returns -1 指示错误。 (TCP 套接字可能 return 0 表示连接关闭,但 UDP 不会发生这种情况,因为它是无连接的。)

@Barmar 在评论中观察到,另一个线程或进程访问同一个套接字原则上可以在调用第一个 recv() 的线程或进程之前读取等待的数据报,但如果这不是问题然后,您随后的 recv() 实际上应该 return 整个数据报,最多达到缓冲区中可用的 space 数量(消息中任何多余的字节都将丢失)。当然,这引出了您为什么要这样做的问题——您还不如跳过第一个 recv(),并在必要时让第二个阻塞。

MSG_TRUNC 添加到标志中不会改变上述任何内容。同样,UDP 套接字以整个数据报为单位运行。唯一的区别是 return 值给出了数据报的大小。 可能是额外 recv() 电话的原因。