为什么在收到所有数据之前,recv
系统调用才会阻塞?每次我看到一个recv
调用时,都会在while循环中继续调用recv
,直到所有数据都存在。为什么不首先让recv
阻止?
答案 0 :(得分:9)
您可以请求recv阻止,直到收到所有数据,并带有MSG_WAITALL
标志。但是,如果信号到达,则执行某些工作(即接收部分数据)的系统调用无法自动重新启动以接收其余信息。因此,即使使用MSG_WAITALL
,也可能会在缓冲区已满之前返回recv调用,并且您必须准备好处理这些情况。鉴于此,许多人只是选择循环,而不是使用鲜为人知的标志,如MSG_WAITALL
。
至于为什么默认情况是这样的,有几个原因可以想到:
telnet
协议,该协议在设计BSD套接字API时很流行。您通常会一次收到少量字节,没有长度字段告诉您需要多少数据,而且您需要立即显示数据。在此处填充缓冲区之前阻塞是没有意义的。与面向行的协议(如SMTP或IMAP)一样,在收到命令之前,您不知道该命令的持续时间。recv
通常用于数据报套接字,它接收单个数据报,即使它比提供的缓冲区小得多。流式套接字的自然扩展就是尽可能多地返回,而无需等待。但最重要的是,既然你需要准备好处理部分缓冲区无论如何,最好强迫人们默认处理它,这样他们就可以提早出现错误。 - 而不是让它们保持隐藏,直到信号到达一个不幸的时刻。
答案 1 :(得分:4)
在大多数情况下,您不知道“所有数据”中有多少数据。例如,如果您在面向行的协议中接收数据,则一行可能是10个字节长或65个字节长。
答案 2 :(得分:2)
您可以将套接字标志更改为阻止或非阻止。您的具体案例实际上与阻止或不阻止无关。
使网络功能按照您默认描述的方式运行是没有意义的 - 如果流永远不会结束......如果程序永远不会结束? Prima facia,这似乎不是健康的默认行为。
阅读http://www.scottklement.com/rpg/socktut/nonblocking.html以熟悉阻止和非阻止IO。