半建立的连接
对于半建立的连接,我的意思是客户端对 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 questions 和 this 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()
才会失败? 欢迎任何帮助,尤其是详细解释的链接。
最佳答案
send
工作正常,因为就客户端而言, session 已建立。发送的数据不必被远端确认才能成功(当数据被复制到内核缓冲区时发送系统调用完成),但见下文。 接收本身永远不会导致错误,因为客户端不需要为接收做任何事情(我的意思是 TCP 协议(protocol));只是在等待。但是一旦你发送了一些数据,你就强制了服务器端的手:它要么已经完成了 session 建立(在这种情况下它可以接受数据)或者它必须发送一个重置(我在这里猜测它不能“保持"未完全建立的 session 中未传递的数据)。
关于sockets - 半建立的 TCP 连接,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37997708/