当连接打开但没有数据发送时,send()和recv()返回什么?

时间:2019-09-03 19:02:22

标签: c sockets

我想接收多个分块发送的请求。为了做到这一点,我正在使用带有recv的TCP套接字。我遍历recv如下:

while ((total_recv < MAX_HEADER) && (received = recv(client, req_buffer, CHUNK, 0)) > 0) {
total_recv += received;
if (strstr(req_buffer, delimiter) != NULL)
    break;
}

我的目标是在收到由定界符标记的标头后停止接收。我不能保证存在定界符,因此如果total_recv大于或等于最大已知标头大小,则会中断循环。

我不喜欢这样。令我困扰的是,我可以收到没有小于最大报头大小的没有分隔符的数据包。在这种情况下,我不得不假设recv将继续增加total_recv直到循环中断。通过读取套接字API,我知道recv将返回读入缓冲区的字节数,如果错误则返回-1,如果连接已关闭则返回0。

是否有更好的方法可以在不依赖超时的情况下循环播放recv?打开连接但发送方或接收方未传输数据时,send()和recv()到底返回什么?

2 个答案:

答案 0 :(得分:2)

如果套接字处于阻止模式(默认),recv()将等待直到有可用数据返回。解决此问题的唯一方法是超时。最简单的方法是使用select()epoll()

如果套接字处于非阻塞模式,则recv()将在没有可用空间时立即返回-1,并且errno将被设置为EWOULDBLOCK。您仍然需要使用某种超时方法,因为这可能仅是由于在接收到所有已发送的数据之前调用recv()太早了。

超时是一种非常脆弱的机制,因为总有可能出现暂时性的网络错误,其持续时间超过超时的时间,并且您会错误地将中断之前的数据视为完整的数据。

也许您可以重新设计协议以更好地处理此问题。让发送者发送带有消息中字节数的前缀,而不是读取分隔符,然后调用recv()直到得到那么多字节。

答案 1 :(得分:1)

是的,您的代码需要改进。

  1. 您需要循环的原因是recv可能返回的值少于完整的标头,即使在标头中稍后出现定界符也是如此。因此,您必须返回并阅读更多内容。

    您的代码中存在一个问题,即第二次调用recv,它将第二次读取到缓冲区的开头。

  2. 您需要测试EOF。

  3. 如果没有数据发送,recv将等待直到有数据发送。 如有必要,它将永远等待, 但是如果套接字关闭,它将返回不成功。