sockets - 半建立的 TCP 连接

标签 sockets tcp network-programming erlang gen-tcp

半建立连接

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

您可以通过在单个监听套接字上启动大量 连接来创建此场景(如果您不调整积压和tcp_max_syn_backlog)。参见 this questionsthis article更多细节。

实验

我进行了几次实验(使用 this code 的变体)并观察到一些我无法解释的行为。所有实验都是使用 Erlang 的 gen_tcp 和当前的 Linux 执行的,但我强烈怀疑答案并非特定于此设置,因此我试图在此处使其更通用。

connect() -> wait -> send() -> receive()

我的出发点是从客户端建立连接,等待 1 到 5 秒,向服务器发送“Ping”消息并等待回复。通过此设置,我观察到 receive() 失败并出现错误 closed 当我建立了一半的连接时。在半建立的连接上 send() 期间从未出现错误。您可以找到此设置的更详细说明 here .

connect() -> 漫长的等待 -> send()

为了查看,如果我在半建立的连接上发送数据时出现错误,我在发送数据前等待了 4 分钟。 4 分钟应涵盖与半建立连接相关的所有超时和重试。仍然可以发送数据,即 send() 无错误返回。

connect() -> receive()

接下来,我测试了如果我只调用 receive() 并且超时时间很长(5 分钟)会发生什么。我的期望是为半建立的连接得到一个 closed 错误,就像在最初的实验中一样。唉,什么也没发生,没有抛出任何错误,接收最终超时。

我的问题

  1. 我称之为半建立的连接是否有一个通用名称?
  2. 为什么 send() 在半建立的连接上成功?
  3. 为什么 receive() 只有在我先发送数据时才会失败?

欢迎提供任何帮助,尤其是指向详细解释的链接。

最佳答案

  1. 从客户端的角度来看, session 已完全建立,它发送 SYN,返回 SYN/ACK 并发送 ACK。只有在服务器端,您才处于半建立状态。 (即使它从服务器收到重复的 SYN/ACK,它也只会重新确认,因为它处于已建立状态。)

  2. 此 session 中的 send 工作正常,因为就客户端而言, session 已建立。发送的数据不必由远端确认才能成功(发送系统调用在数据复制到内核缓冲区时完成),但请参见下文。

  3. 我相信发送实际上在连接上生成错误(可能是 RST),因为接收系统无法在尚未完成建立的 session 上确认数据。我的猜测是 任何 引用客户端套接字的系统调用发生在发送后加上一个短暂的延迟(即当 RST 有机会返回时)将导致错误。

    接收本身永远不会导致错误,因为客户端不需要为接收做任何事情(我的意思是 TCP 协议(protocol));它只是在无所事事地等待。但是一旦你发送了一些数据,你就强制了服务器端的手:它要么已经完成了 session 建立(在这种情况下它可以接受数据)要么它必须发送一个重置(我在这里猜测它不能“保持” "未完全建立的 session 中未传送的数据)。

关于sockets - 半建立的 TCP 连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37997708/

相关文章:

java - 等待API服务器的响应

c++ - C++中的UDP广播实现

用于工作站客户端的 c# 热图像服务器流

c# - 如何通过 TCP 和 protobuf-net 接收包

c++ - Boost asio::deadline_timer 在超时前重置

c - 段错误将指针传递给函数

c - 为什么我对 connect() 的调用失败了?

java - 从池中消除突然关闭的套接字,Java

连接功能时常失效?

c - gethostbyname() 之后的本地 IP