Socket关闭时遇在途数据包及客户端主动关闭场景的技术问询
TCP Socket关闭场景的两个核心问题解答
让我逐个拆解这两个实际开发中容易碰到的TCP关闭场景问题:
问题1:当Socket正在关闭时,对方的数据包仍在传输途中,会发生什么情况?
首先得明确,TCP的关闭是四次握手的异步过程,不是调用close()就瞬间断开连接的,得看“正在关闭”处于哪个阶段:
- 如果你是主动关闭方,刚调用
close()发起FIN包,处于FIN_WAIT_1或FIN_WAIT_2状态:
内核会继续正常接收对方传来的数据包,把它们存入接收缓冲区,同时给对方回复ACK。直到对方也发送FIN包,你的内核才会完成后续握手流程,进入TIME_WAIT状态。
这里要注意:一旦你调用了close(),应用层就不能再通过这个Socket描述符读取数据了,但内核会默默完成数据接收和TCP握手的收尾工作。 - 如果是对方先发起关闭,你处于
CLOSE_WAIT状态(还没调用close()发自己的FIN):
这时候你不仅能正常接收对方的数据包,甚至还可以继续给对方发送数据,直到你主动调用close()发起自己的FIN包为止。
简单总结:只要TCP连接还没走完四次握手的全部流程,内核都会按正常TCP逻辑处理对方的数据包,不会直接丢包或发送RST包。
问题2:客户端主动关闭连接(未设置SO_LINGER),close函数立即返回后,收到服务器最后一批数据的情况
这个场景很容易让开发者产生误解,核心要搞清楚close()的行为和TCP连接状态的区别:
- 当客户端调用
close()且未设置SO_LINGER时,close()会立即返回,释放应用层的Socket描述符,但TCP的关闭流程是由内核在后台异步处理的——此时FIN包可能还在网络传输中,客户端和服务器的TCP连接并没有彻底断开。 - 当服务器的最后一批数据比FIN包先到达客户端时,内核会正常接收这些数据,并存入对应的TCP接收缓冲区。但因为应用层的Socket描述符已经被释放,你的应用程序无法再读取这些数据了。
- 客户端绝对不会发送RST包!RST是用来处理异常场景的(比如收到不属于当前连接的数据、连接彻底关闭后收到数据),而这个场景属于TCP关闭过程中的正常交互,内核只会回复ACK给服务器。
- 那些没被应用读取的数据,最终会在TCP连接彻底关闭完成后,被内核自动丢弃。
内容的提问来源于stack exchange,提问作者Ace
相关产品推荐
相关产品推荐

