【问题标题】:TCP - What if client call close() before server accept()TCP - 如果客户端在服务器 accept() 之前调用 close() 会怎样
【发布时间】:2020-11-20 22:42:57
【问题描述】:

在 C/C++ 中,如果客户端和服务器完成了 3 次握手,并且此连接位于服务器的积压(侦听队列)中。在服务器调用accept()之前,如果客户端调用close()会发生什么。是否会从积压中删除此连接?

现实世界的情况是,服务器有时太忙而无法立即接受每个连接。所以会有一些连接在积压中等待。客户端对来自服务器的第一个响应有超时。如果发生超时,它将调用close() 然后重试或其他什么。此刻,我想知道服务器的积压是否会从积压中删除连接。

请分享您的想法。赞一个!

【问题讨论】:

标签: c++ c sockets networking tcp


【解决方案1】:

一般来说,如果客户端调用close(),客户端协议栈会发送一个FIN,表示客户端发送完毕,并等待服务器发回一个FIN,ACK给客户端(赢了) '在服务器接受连接之前不会发生,正如我们将看到的),然后客户端将确认。这将是 TCP 连接的正常终止。

但是,由于 TCP 连接由两个或多或少独立的流组成,因此从客户端发送 FIN 实际上只是客户端完成发送数据的声明(这通常称为“半关闭”),并且实际上并不是在 TCP 协议级别关闭连接的请求(尽管更高级别的协议通常会以这种方式解释它,但它们只能在连接被接受并且它们已经读取返回 0 字节后才能这样做,以便了解客户已完成写作)。服务器仍然可以继续发送数据,但是由于客户端调用了close(),因此无法再将这些数据传递给客户端应用程序。如果服务器进一步发送数据,客户端上的协议栈将响应复位,导致 TCP 连接异常终止。如果客户端在声明发送数据完成后确实希望继续从服务器接收数据,它应该通过调用shutdown(sock,SHUT_WR)而不是调用close()来实现。

所以这意味着超时并且通常被客户端关闭的连接通常会在服务器上保持活动状态,并且服务器将能够接受它们、读取请求、处理请求并发送回复,然后才发现当客户端返回重置时应用程序无法再读取回复。我说“一般”的原因是防火墙、代理和操作系统协议栈都限制了 TCP 连接可以保持半关闭状态的时间,这通常违反相关的 TCP RFC,但出于“有效”的原因,例如处理 DDOS。

我认为您担心的是,由于客户端超时和重试,过载的服务器会进一步过载,根据我之前的解释,我认为这是正确的。为了避免这种情况,客户端超时可以在调用 close() 之前将 SO_LINGER 设置为 0,这将导致发送重置以导致立即异常终止。我还建议在超时时使用指数回退来进一步减轻对过载服务器的影响。

【讨论】:

  • 有一点是 TCP 本身没有客户端或服务器。它在两个平等的对等点之间建立连接,您所描述的可能从任何一方发生。客户端/服务器概念是一个应用程序概念。
  • @RonMaupin 同意了。我只是使用正在进行客户端服务器操作的 OP 的语言。
  • 感谢您的回答。你居然预言了我自己错误造成的DDOS。并且还提供了我和我的同事在阅读您的回答之前讨论过的指数回退解决方案。欣赏!
【解决方案2】:

3 次握手完成后,连接处于 ESTABLISHED 状态。在客户端,它可以立即开始发送数据。在服务器端,连接被放置在accept() 可以从中提取的状态/队列中,以便应用程序可以使用连接(请参阅How TCP backlog works in Linux)。

如果服务器没有accept() 连接,则连接仍然是 ESTABLISHED,它的入站缓冲区将简单地填满客户端发送的任何数据(如果有)。

如果客户端在调用accept()之前断开连接,那么连接仍然进入CLOSED状态,并且会从accept()拉出的队列中移除。应用程序永远不会看到连接。

【讨论】:

  • 你能被说服学习 rust - 我们需要那个语言的响应专家,就像你在 c++ 中一样:-)
  • 一个 TCP 连接在每个方向都有一个流。当客户端调用close() 时,它将发送一个 FIN 并且连接将“半关闭”; TCP 状态图不会直接从 ESTABLISHED 移动到 CLOSED。请注意,在协议级别,调用 close() 与 shutdown(sock,SHUT_WR) 无法区分,后者允许客户端继续从服务器读取流。如果在close() 之后收到任何数据,则会触发 RST,但必须接受套接字才能发生这种情况。
猜你喜欢
  • 2016-07-29
  • 2020-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-03
  • 1970-01-01
  • 2013-08-20
  • 2012-01-04
相关资源
最近更新 更多