C套接字可以在没有客户端关闭连接的情况下收集0个字节吗?

dmo*_*221 5 c sockets recv server

我在C中实现了一个Web服务器.它调用recv()一个连接的阻塞套接字来接收传入的HTTP请求.Linux手册页recv()在阻塞套接字上说明了以下内容:

如果套接字上没有可用的消息,则接收呼叫等待消息到达...接收呼叫通常返回任何可用的数据,直到请求的数量,而不是等待接收所请求的全部金额.

...

这些调用返回接收的字节数,如果发生错误则返回-1 ...当对等体执行有序关闭时,返回值将为0.

因此,要接收完整请求,我的服务器代码包含以下形式的循环:

int connfd; // accepted connection
int len;    // # of received bytes on each recv call

...

while (/* HTTP message received so far has not terminated */) {
  len = recv(connfd, ...);
  if (len == 0) {
    // close connfd, then escape loop
  } else if (len < 0) {
    // handle error
  } else {
    // process received bytes
  }
}    
Run Code Online (Sandbox Code Playgroud)

我的问题:recv()由于网络问题而没有客户端执行有序关闭,是否有可能返回0个字节,从而导致我的代码过早地退出循环?手册页含糊不清.

Joh*_*ger 7

TL; DR:POSIX说"不".

我不认为手册页不是那么清楚,但POSIX的描述可能更清楚一点:

recv()函数应从连接模式或无连接模式套接字接收消息.

[...]

成功完成后,recv()应以字节为单位返回消息的长度.如果没有可用的消息接收并且对等体已经执行了有序关闭,recv()则应返回0.否则,应返回-1并errno设置为指示错误.

因此,POSIX正好有三种选择:

  • recv()成功接收消息并返回其长度.根据定义,长度是非零的,因为如果没有收到字节,则没有收到消息.recv()因此返回大于0的值.

  • 没有收到来自对等方的消息,我们相信没有任何消息即将发布,因为对等方已经(在recv()返回时)执行了有序的连接关闭.recv()返回0.

  • "否则"发生了其他事情.recv()返回-1.

在任何情况下,recv()如果没有可用数据且套接字上没有错误条件,则将阻塞,除非套接字处于非阻塞模式.在非阻塞模式下,如果在recv()调用时既没有数据也没有错误条件,则属于"其他"情况.

人们不能完全排除给定系统不符合POSIX,但你必须以某种方式决定你将如何解释功能结果.如果您在声称符合POSIX的系统上调用POSIX定义的函数(至少就该函数而言),则很难依赖于POSIX语义.

  • 在“SOCK_DGRAM”或“SOCK_SEQPACKET”套接字的情况下,第一点是不正确的,它们可以具有0长度的消息。但是,OP 似乎隐含地询问了“SOCK_STREAM”,因为它通常用于传输 HTTP (2认同)