您可以使用MSG_WAITALL标志请求该recv块,直到接收到所有数据为止。但是,如果信号到达,执行了某些工作(即,接收部分数据)的系统调用不能自动重启以接收其余部分。因此,即使使用MSG_WAITALL,也存在recv调用可能在缓冲区满之前返回的情况,您必须准备好处理这些情况。鉴于此,许多人简单地选择循环,而不使用鲜为人知的标志,如MSG_WAITALL。
至于为什么在默认情况下会出现这种情况,我会想到以下几个原因:
通常您希望接收部分读取。例如,如果您正在递增地显示传入的数据,或者如果您将其代理到其他地方,或者如果数据太大,您无法一次在内存中缓冲整个数据。毕竟,如果您只是立即写入文件,您是否关心将其拆分为200次写入,而不是比方说150次写入?有时您甚至不知道一开始需要多少数据。考虑一下telnet协议,它在BSD sockets设计的时候很流行。你通常一次只能收到几个字节,没有长度字段告诉你需要多少数据,而且你需要立即显示这些数据。在这里填充缓冲区之前,阻塞是没有意义的。同样,对于面向行的协议,例如SMTP或IMAP -在收到所有it.recv之前,您不知道命令有多长。在数据报套接字中,它接收单个数据报,即使它比提供的缓冲区小得多。对流套接字的自然扩展是不需要等待就能返回尽可能多的内容。
但最重要的是,因为无论如何你都需要准备好处理部分缓冲区,所以强制人们默认处理它是很好的,这样他们就会在循环中提早发现bugs而不是让它们隐藏起来,直到信号到达不幸的时刻。