为什么在收到所有数据之前,recv系统调用不直接阻塞?每次我看到一个recv调用时,它都在一个while循环中,一直调用recv直到所有数据都存在为止。为什么不先设置recv块?

最佳答案

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

07-24 18:23
查看更多