【问题标题】:What do send() and recv() return when a connection is open but no data is being sent?当连接打开但没有发送数据时,send() 和 recv() 会返回什么?
【发布时间】:2019-09-03 19:02:22
【问题描述】:

我想接收分块发送的请求。为了做到这一点,我使用了一个带有 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() 究竟返回了什么?

【问题讨论】:

  • "我的目标是在我收到以分隔符结尾的标头时停止接收" - 那么您可能需要读取 1 个字符直到到达分隔符的时间。如果标头的大小不是CHUNK 的偶数倍,那么您的recv 循环将在到达标头末尾时读取太多数据。此外,您对strstr() 的使用已被破坏,因为req_buffer 不是以空值终止的,并且您没有在每次循环迭代时将收到的每个req_buffer 连接到累积缓冲区中。
  • "我不能保证分隔符存在" - 为什么不呢?您正在使用哪种协议,它不能保证存在分隔符?如果基于 TCP 的协议不提供任何可靠地检测标头结尾的方法,这将是非常不寻常且非常不稳定的。您确定实际标头大小未在标头本身内编码吗?当不使用终止分隔符时,这会更有意义。

标签: c sockets


【解决方案1】:

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

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

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

也许您可以重新设计协议以更好地处理这个问题。与其一直读到分隔符,不如让发件人发送一个带有消息中字节数的前缀,然后调用recv(),直到获得那么多字节。

【讨论】:

    【解决方案2】:

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

    1. 您需要循环的原因是recv 可能返回少于完整的标头,即使在标头稍后会出现分隔符。所以你必须循环回来阅读更多内容。

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

    2. 您需要测试 EOF。

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

    【讨论】:

    • 我不确定 EOF 是 0 还是 -1,也无法通过在线文档进行确认。但是,我可能会将它与 get 函数混淆,后者必须使用 0 表示零字节。
    • Per POSIX: "成功完成后,recv() 将返回消息的长度(以字节为单位)。如果没有可接收的消息并且对等方已执行有序关闭,recv()应返回 0。否则,应返回 -1 并设置 errno 以指示错误。"
    • 并且来自online man page:“当流套接字对等方执行了有序关闭时,返回值将为 0(传统的“文件结束”返回)。”
    • 谢谢。我找到了那个页面或类似的页面,但不知何故找不到提到 EOF 的返回值部分。
    猜你喜欢
    • 1970-01-01
    • 2012-09-21
    • 1970-01-01
    • 2018-02-17
    • 2016-08-22
    • 1970-01-01
    • 2014-10-25
    • 2020-08-14
    • 1970-01-01
    相关资源
    最近更新 更多