TCP关闭连接 - 不容易
(1) 收到rst后,内核会立马释放该TCP连接所占用的内存资源(状态、数据)、以及端口号。
(2) 收到rst后,应用层首次读,read返回-1,并设置errno为ECONNRESET。POLLIN 会立刻再次触发,再read会返回0。
(3) 收到rst后,应用层首次写,(此时写操作返回EPIPE错误)内核向该进程发送一个SIGPIPE信号,该信号的默认行为是终止进程,因此进程必须捕获它以免不情愿地被终止。
对于本端来讲,关闭一个TCP连接只有两种情况:
(1)RST,相当于重置了。
(2)关掉本端写(即发送FIN分节),而无法主动关闭对端写,也就是只能主动关闭半个连接,另外一个方向连接的关闭是对端主动进行的。
(3)假如本端收到对端的FIN分节后(即read返回0),是无法判断对端究竟是close(对端也不读了)还是shutdown(对端还可以读,半关闭)。
Q : 那么此时,我们再去wirte会怎么样呢?
1、客户端可能调用shutdown(cfd, SHUT_WR),即单向关闭了它的写端,于是我read到0,这种情况我不想马上关闭这个连接,而是把给这个客户的回复都写完后再关闭。
2、客户端可能调用close(cfd)。这时我如果write(sfd, buf2,size2),就会返回EPIPE错误。
Q : 当read返回0后,该怎么办呢?
此时是否要close取决于你的应用。通常来说如果对方调用的是close,那么你也可以close。否则你不能close,例如对方发送一个包给你并shutdown write然后调用recv,这时候你还可以返回一个或多个包,连接此时处于半关闭状态,可以一直持续。 摘自 知乎 胡宇光
Q : FIN_WAIT2 和CLOSE_WAIT这两状态会一直持续下去么?
【参考】
https://www.yuque.com/infuq/others/yyvoa7#cDrZq
https://blog.csdn.net/huangyimo/article/details/81297805
https://blog.csdn.net/qq_35733751/article/details/80146161
【补充面试题】
1.如何避免TCP的TIME_WAIT状态(高并发)