【问题标题】:Socket recv() function套接字 recv() 函数
【发布时间】:2019-07-14 05:03:27
【问题描述】:

在 c++ 中,在 windows 操作系统中,在 recv() 调用 TCP 套接字时,如果套接字连接以某种方式关闭,recv() 将立即返回还是会挂起?

阻塞和非阻塞套接字的结果(立即返回或挂起)是什么? 我正在使用套接字版本 2。

提前致谢。

【问题讨论】:

  • posix 套接字?
  • 标准 C++ 中没有 recv(),因此在您指定使用的网络 API 之前,您的问题将是不完整的,对其他人没有帮助。

标签: c++ winsock winsock2


【解决方案1】:

recv() 将在 graceful 断开连接时返回 0,即对等端关闭其连接端并且其套接字堆栈向您的套接字堆栈发送了一个 FIN 数据包。无论您使用阻塞套接字还是非阻塞套接字,都可以保证立即获得此结果。

recv() 将在任何其他错误时返回 -1,包括异常 连接丢失。 您需要使用WSAGetLastError() 来了解实际发生的情况。对于阻塞套接字上的丢失连接,您通常会收到错误代码,例如 WSAECONNRESETWSAECONNABORTED。对于非阻塞套接字上的丢失连接,recv() 可能会立即报告WSAEWOULDBLOCK 错误,然后在稍后的某个时间报告实际错误,可能通过select() 例外fd_set,或者异步通知,具体取决于您如何实现非阻塞逻辑。

但是,无论哪种方式,都不能保证您及时获得连接丢失的失败结果!在操作系统认为连接实际丢失并使套接字连接无效之前,可能需要一些时间(秒、分钟,在极少数 情况下甚至可能是几个小时)。 TCP设计是为了尽可能恢复丢失的连接,因此它必须考虑临时网络中断等,因此存在内部超时。您在代码中看不到它,它发生在后台。

如果您不想等待操作系统在内部超时,您可以随时在代码中使用自己的超时,例如通过select()setsocktopt(SO_RCVTIMEO)、TCP keep-alives(setsockopt(SO_KEEPALIVE) 或 @ 987654334@) 等。您可能仍然不会立即遇到故障,但您迟早会得到它。

【讨论】:

    【解决方案2】:

    As documented 取决于连接的关闭方式,在非正常情况下,它应该或多或少立即返回值SOCKET_ERROR,并将WSAGetLastError 设置为WSAENOTCONN 等可能原因之一,或者只是在优雅的连接关闭场景中返回0。这在阻塞和非阻塞套接字之间是一样的。

    如果套接字是面向连接的,并且远程端已经优雅地关闭了连接,并且所有数据都已接收到,recv 将立即完成,接收到零字节。如果连接已被重置,recv 将失败并返回错误 WSAECONNRESET。

    但是,由于我知道 Windows API 并不总是按文档说明工作,因此我建议对其进行测试。

    【讨论】:

      【解决方案3】:

      如果您的recv() 是基于 BSD - 几乎所有都是 - 如果连接关闭(根据本地端的状态),它将立即返回,无论套接字是阻塞还是非阻塞。

      【讨论】:

      • 如果连接没有关闭但在另一边挂起,它会挂起,但它是一个阻塞套接字(尽管这有点超出了问题的范围)。
      • @SimonDoppler:所有这些调用都是从本地的角度工作的/当然本地状态会延迟以反映另一端刚刚发生的事情,而且可能会很长。跨度>
      猜你喜欢
      • 2013-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-23
      • 1970-01-01
      • 2013-11-06
      相关资源
      最近更新 更多