4

半建立连接

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

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

实验

我进行了几次实验(使用此代码的变体)并观察到一些我无法解释的行为。所有实验都是使用 Erlanggen_tcp和当前的 Linux 进行的,但我强烈怀疑答案并不特定于这个设置,所以我试图在这里保持更通用。

connect()-> 等待 -> send()->receive()

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

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

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

connect()->receive()

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

我的问题

  1. 我所说的半建立连接有一个通用名称吗?
  2. 为什么send()半建立连接成功?
  3. receive()如果我先发送数据,为什么 a only 会失败?

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

4

1 回答 1

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

  2. send会话上的 工作正常,因为就客户端而言,会话已建立。发送的数据不必为了成功而被远端确认(当数据被复制到内核缓冲区时,发送系统调用完成),但见下文。

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

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

于 2016-06-23T17:37:14.890 回答