半建立的连接

对于半建立的连接,我的意思是客户端对 connect() 的调用成功返回的连接,但服务器对 accept() 的调用没有成功返回。这可以通过以下方式发生:客户端调用 connect() ,导致向服务器发送 SYN 数据包。服务器进入 SYN-RECEIVED 状态并向客户端发送 SYN-ACK 数据包。这会导致客户端回复 ACK ,进入状态 ESTABLISHED 并从 connect() 调用返回。如果最终的 ACK 丢失(或被忽略,由于服务器上的接受队列已满,这可能是更可能的情况),服务器仍处于 SYN-RECEIVED 状态并且 accept() 不会返回。由于与 SYN-RECEIVED 状态相关的超时,将重新发送 SYN-ACK ,从而允许客户端重新发送 ACK 。如果服务器最终能够处理 ACK,它也会进入状态 ESTABLISHED。否则它最终会重置连接(即向客户端发送 RST)。

您可以通过在单个监听套接字上启动大量连接来创建此场景(如果您不调整 backlog 和 tcp_max_syn_backlog )。有关更多详细信息,请参阅 this questionsthis article

实验

我进行了几次实验(使用 this code 的变体)并观察到一些我无法解释的行为。所有的实验都是使用 Erlang 的 gen_tcp 和当前的 Linux 进行的,但我强烈怀疑答案不是特定于这个设置的,所以我试图在这里保持更通用。
connect() -> 等待 -> send() -> receive()
我的出发点是从客户端建立连接,等待 1 到 5 秒,向服务器发送“Ping”消息并等待回复。通过此设置,我观察到 receive() 失败并出现错误 closed 当我建立半连接时。在半建立的连接上的 send() 期间从来没有错误。您可以在 here 中找到有关此设置的更详细说明。
connect() -> 长时间等待 -> send()
看看,如果我在半建立的连接上发送数据时出现错误,我在发送数据之前等待了 4 分钟。 4 分钟应涵盖与半建立连接相关的所有超时和重试。仍然可以发送数据,即 send() 返回没有错误。
connect() -> receive()
接下来我测试了如果我只在很长的超时(5 分钟)内调用 receive() 会发生什么。我的期望是在半建立的连接中得到 closed 错误,就像在原始实验中一样。唉,什么也没发生,也没有抛出错误,接收最终超时。

我的问题

  • 我所说的半建立连接有一个通用名称吗?
  • 为什么半建立连接上的send() 成功?
  • 为什么只有当我先发送数据时 receive() 才会失败?

  • 欢迎任何帮助,尤其是详细解释的链接。

    最佳答案

  • 从客户端的角度来看, session 完全建立,它发送 SYN,收到 SYN/ACK 并发送 ACK。只有在服务器端,您才具有半建立状态。 (即使它从服务器收到重复的 SYN/ACK,它也会重新 ACK,因为它处于已建立的状态。)
  • 此 session 上的 send 工作正常,因为就客户端而言, session 已建立。发送的数据不必被远端确认才能成功(当数据被复制到内核缓冲区时发送系统调用完成),但见下文。
  • 我在这里相信发送实际上是在连接上产生错误(可能是 RST),因为接收系统无法在尚未完成建立的 session 上确认数据。我的猜测是,在发送后发生的任何引用客户端套接字的系统调用加上短暂的延迟(即当 RST 有机会返回时)都会导致错误。
    接收本身永远不会导致错误,因为客户端不需要为接收做任何事情(我的意思是 TCP 协议(protocol));只是在等待。但是一旦你发送了一些数据,你就强制了服务器端的手:它要么已经完成了 session 建立(在这种情况下它可以接受数据)或者它必须发送一个重置(我在这里猜测它不能“保持"未完全建立的 session 中未传递的数据)。
  • 关于sockets - 半建立的 TCP 连接,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37997708/

    10-12 01:12