网络知识(1) - TCP连接关闭四次挥手
source link: https://www.tuicool.com/articles/vuUVVzA
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
本文包含内容:
- TCP FIN 简介
- TCP ACK 简介
- 为什么 TCP 连接关闭是四次挥手
- 先看最常见的正常关闭流程
- 什么时候进入
CLOSING
状态 -
TIME_WAIT
状态的作用 - 为什么
被动关闭端
不需要维持一个类似TIME_WAIT
的状态,万一发出的 ACK 也丢失了呢 - 最后,再奉上一张 geek 味十足的tcp状态迁移图
TCP FIN 简介
FIN可以理解为TCP包中的一种信令类型。事实上,FIN是TCP包头中的一个固定标志位,该标志位为1时,表示本端关闭连接。
TCP ACK 简介
TCP基于IP协议,IP包不保证可靠传输。
TCP的做法是,发送端发送的每个TCP包携带序号信息,接收端通过序号处理乱序包和重复包。
并且,接收端持续向发送端发送ACK信息,反馈接收端接收到的流式数据的位置,从而使得发送端有能力检测出对端未接收到数据,发送端可重新发送丢失的数据。
为什么 TCP 连接关闭是四次挥手
由于TCP可双向发送数据,所以TCP连接关闭至少需要两次挥手,即两端各自发送FIN,表示本端已无数据需要发送。
又由于FIN包也有丢失的可能,所以出现了ACK of FIN,即对FIN包也回复ACK确认,以保证FIN包丢失后可以重传。
事实上,由于FIN和ACK of FIN都有可能丢失,TCP连接关闭的设计比四次挥手通常被理解的情况要更复杂些。
我们接下来看。
先看最常见的正常关闭流程
提示,本文的后续内容建议结合上面的 TCP连接关闭状态连接图
配套食用。
以下 主动关闭端
指未收到对端FIN的情况下本端发送FIN。 被动关闭端
则是先收到对端发送的FIN,之后某个时间点本端发送FIN。
主动关闭端
流程为: 发送FIN,接收ACK,接收FIN,发送ACK
状态迁移为: ESTAB
-> FINWAIT_1
-> FINWAIT_2
-> TIME_WAIT
-> CLOSED
被动关闭端
流程为: 接收FIN,发送ACK,发送FIN,接收ACK
状态迁移为: ESTAB
-> CLOSE_WAIT
-> LAST_ACK
-> CLOSED
什么时候进入 CLOSING
状态
有两种情况:
第一种,由于ACK of FIN可能丢失,所以当 被动关闭端
发出的ACK丢失,而 被动关闭端
紧接着又发出了FIN,那么 主动关闭端
会先收到FIN,从而进入 CLOSING
状态。
第二种,两端都在还未收到FIN的的情况,发出了FIN,即两端同时关闭,那么可能出现发出FIN后还没收到对应的ACK,立马就收到对端发出的FIN。第二种情况下,两端都是 主动关闭端
,它们都是首先从 ESTAB
状态进入 FINWAIT_1
状态,不再走 CLOSE_WAIT
那条状态迁移路线。
TIME_WAIT
状态的作用
简单来说,由于ACK of FIN存在丢失的可能。 主动关闭端
向 被动关闭端
回复的ACK of FIN可能丢失(此ACK为 主动关闭端
发出的最后一个包)。而TCP是不会再去对ACK做ACK确认的。
那么如果出现 主动关闭端
发出的ACK丢失了的情况, 被动关闭端
由于收不到ACK将停留在 LAST_ACK
状态,无法进入 CLOSED
状态。
TCP协议处理这种异常情况的做法是: 被动关闭端
如果收不到ACK将触发超时重新发送FIN;在 主动关闭端
维持一个 TIME_WAIT
,继续接收FIN并作出ACK回复。
TIME_WAIT
的维持时间是2个MSL,MSL是Maximum Segment Lifetime的缩写,即报文最大生存时间。
其实讲到这我们已经可以知道,作为 主动关闭端
,进入 TIME_WAIT
状态并维持一段时间是TCP协议本身的设计,并不是一种异常状态。
之后我会再单独针对 TIME_WAIT
写一篇文章,描述 TIME_WAIT
的维持时间为什么是2个MSL, TIME_WAIT
的一些内核相关参数的设置,以及服务器上出现大量 TIME_WAIT
时我们应该怎么办。
为什么 被动关闭端
不需要维持一个类似 TIME_WAIT
的状态,万一发出的 ACK 也丢失了呢
我在学习TCP连接关闭时,有一个疑问,既然 主动关闭端
为了解决发送的ACK丢失,维持了一个 TIME_WAIT
状态。
那么 被动关闭端
发出的ACK也可能丢失,如果这个ACK丢失(其他包都未丢失), 被动关闭端
会顺利进入 CLOSED
状态,那么 主动关闭端
岂不是会一直停留在 CLOSING
状态。
后来在网上询问了一些高手,他们的解释是并不会出现这种情况。
理解这个问题,首先要理解ACK of FIN可以是一个单独的TCP包,也可以不是。
事实上,ACK信息也是TCP包头中的一个固定字段。
所以,当 被动关闭端
关闭连接发送FIN时,FIN中的ACK字段也会携带对端发出FIN所对应的ACK信息。只要 主动关闭端
收到了这个FIN,也即可以确认对端已经收到了本端发出的FIN。
这种情况下,可以理解为 主动关闭端
在 FINWAIT_1
收到FIN后,进入 CLOSING
状态,之后迅速进入了 TIME_WAIT
状态。
最后,奉上一张geek味十足的tcp状态迁移图
图片来源: RFC 793 - Transmission Control Protocol ( https://tools.ietf.org/html/rfc793 )
另外从中可以看到, SYN_RCVD
状态也可以发送FIN从而进入 FINWAIT_1
。
+---------+ ---------\ active OPEN | CLOSED | \ ----------- +---------+<---------\ \ create TCB | ^ \ \ snd SYN passive OPEN | | CLOSE \ \ ------------ | | ---------- \ \ create TCB | | delete TCB \ \ V | \ \ +---------+ CLOSE | \ | LISTEN | ---------- | | +---------+ delete TCB | | rcv SYN | | SEND | | ----------- | | ------- | V +---------+ snd SYN,ACK / \ snd SYN +---------+ | |<----------------- ------------------>| | | SYN | rcv SYN | SYN | | RCVD |<-----------------------------------------------| SENT | | | snd ACK | | | |------------------ -------------------| | +---------+ rcv ACK of SYN \ / rcv SYN,ACK +---------+ | -------------- | | ----------- | x | | snd ACK | V V | CLOSE +---------+ | ------- | ESTAB | | snd FIN +---------+ | CLOSE | | rcv FIN V ------- | | ------- +---------+ snd FIN / \ snd ACK +---------+ | FIN |<----------------- ------------------>| CLOSE | | WAIT-1 |------------------ | WAIT | +---------+ rcv FIN \ +---------+ | rcv ACK of FIN ------- | CLOSE | | -------------- snd ACK | ------- | V x V snd FIN V +---------+ +---------+ +---------+ |FINWAIT-2| | CLOSING | | LAST-ACK| +---------+ +---------+ +---------+ | rcv ACK of FIN | rcv ACK of FIN | | rcv FIN -------------- | Timeout=2MSL -------------- | | ------- x V ------------ x V \ snd ACK +---------+delete TCB +---------+ ------------------------>|TIME WAIT|------------------>| CLOSED | +---------+ +---------+
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK