为什么在收到所有数据之前不会阻止recv?

时间:2012-01-09 03:20:44

标签: python c sockets network-programming

为什么在收到所有数据之前,recv系统调用才会阻塞?每次我看到一个recv调用时,都会在while循环中继续调用recv,直到所有数据都存在。为什么不首先让recv阻止?

3 个答案:

答案 0 :(得分:9)

您可以请求recv阻止,直到收到所有数据,并带有MSG_WAITALL标志。但是,如果信号到达,则执行某些工作(即接收部分数据)的系统调用无法自动重新启动以接收其余信息。因此,即使使用MSG_WAITALL,也可能会在缓冲区已满之前返回recv调用,并且您必须准备好处理这些情况。鉴于此,许多人只是选择循环,而不是使用鲜为人知的标志,如MSG_WAITALL

至于为什么默认情况是这样的,有几个原因可以想到:

  • 您经常希望接收部分读取。例如,如果您正在逐步显示数据,或者您将数据代理到其他地方,或者如果数据太大,则无法立即将整个数据缓冲在内存中。毕竟,如果您只是立即写入文件,您是否关心将其拆分为200次而不是150次?
  • 有时您甚至不知道一开始就需要多少数据。考虑telnet协议,该协议在设计BSD套接字API时很流行。您通常会一次收到少量字节,没有长度字段告诉您需要多少数据,而且您需要立即显示数据。在此处填充缓冲区之前阻塞是没有意义的。与面向行的协议(如SMTP或IMAP)一样,在收到命令之前,您不知道该命令的持续时间。
  • recv通常用于数据报套接字,它接收单个数据报,即使它比提供的缓冲区小得多。流式套接字的自然扩展就是尽可能多地返回,而无需等待。

但最重要的是,既然你需要准备好处理部分缓冲区无论如何,最好强迫人们默认处理它,这样他们就可以提早出现错误。 - 而不是让它们保持隐藏,直到信号到达一个不幸的时刻。

答案 1 :(得分:4)

在大多数情况下,您不知道“所有数据”中有多少数据。例如,如果您在面向行的协议中接收数据,则一行可能是10个字节长或65个字节长。

答案 2 :(得分:2)

您可以将套接字标志更改为阻止或非阻止。您的具体案例实际上与阻止或不阻止无关。

使网络功能按照您默认描述的方式运行是没有意义的 - 如果流永远不会结束......如果程序永远不会结束? Prima facia,这似乎不是健康的默认行为。

阅读http://www.scottklement.com/rpg/socktut/nonblocking.html以熟悉阻止和非阻止IO。