TCP三次握手四次断开及11种状态转变
- 置位概念: 根据TCP的包头字段,存在三个重要的标识ACK、SYN、FIN
- ACK: 表示验证字段
- SYN: 位数置为1,表示建立TCP连接
- FIN: 位数置为1,表示断开TCP连接
1、三次握手
建立过程:
- 由客户端发送建立TCP连接的请求报文,其中报文中包含
seq序列号
,是由发送端随机生成
的,并且还将报文中SYN字段置为1
,表示需要建立TCP连接。 - 服务端会回复客户端发送的TCP连接请求报文,其中包含
seq序列号
,是由回复端随机生成
的,并且将回复报文的SYN字段置1,而且会产生ACK字段,ACK字段数值是在客户端发过来的seq序列号基础上加1进行回复,以便客户端收到信息时,知晓自己的TCP建立请求已得到了验证。 - 客户端收到服务端发送的TCP建立验证请求后,会使自己的
seq序列号加1
表示,并且再次回复ACK验证请求,ACK在服务端发送过来的seq基础上加1,进行回复。
建立过程状态机转变:
- 一开始建立连接之前服务端和客户端的状态都为
CLOSED
。 - 服务端
创建socket
后开始监听,变为LISTEN
状态。 - 客户端建立请求连接,向服务端发送SYN报文,客户端的状态变为
SYN_SENT
。 - 服务端收到客户端的报文后会向客户端发送ACK和SYN报文,此时服务端的状态变为
SYN_RCVD
。 - 然后,客户端收到ACK和SYN,会向服务器发送ACK,客户端状态变为
ESTABLISHED
,服务端收到客户端的ACK 后也变为ESTABLISHED
。 - 至此,TCP3次握手完成,建立连接!
tcpdump抓包分析tcp三次握手和四次断开:
命令:
tcpdump port 22 -Stn -c 3
参数说明:
port:指定端口
-S:用绝对而非相对数值列出TCP关联数
-t:在每列倾倒资料上不显示时间戳记
-n:不把主机的网络地址转换成名字
-c <数据包数目>:收到指定的数据包数目后,就停止进行的操作
Flags说明:
[S]代表seq
[S.]代表seq和ack
[.]代表ack
[F]代表FIN
[P]代表有DATA数据传输
[R]代表连接重置
[E]代表ECN-Echo(不了解)
[w]代表ECN CWR(不了解)
- 看Flags标识:
- 10.0.0.1 > 10.0.0.77:Flags为[
SEW
],这里看S即可,为SYN连接请求 - 10.0.0.77 > 10.0.0.1:Flags为[
S.E
],这里看S和.即可,S
代表SYN回复,.
代表ack - 10.0.0.1 > 10.0.0.77:Flags为[
.
],即为ack确认,此时TCP三次握手建立成功
2、四次断开
断开过程:
- 服务端发送断开TCP连接请求的报文,其中报文中包含seq序列号,是由发送端随机生成的,并且还将报文中FIN字段置为1,表示需要断开TCP连接。
- 客户端会回复服务端发送的TCP断开请求报文,其中包含seq序列号,是由回复端随机生成的,而且会产生ACK字段,ACK字段数值,是在服务端发过来的seq序列号基础上加1进行回复,以便服务端收到信息时,知晓自己的TCP断开请求已得到了验证。
- 客户端在回复完服务端的TCP断开请求后,不会马上就进行TCP 连接的断开,客户端会先确保断开前,所有传输到服务端的数据是否已经传输完毕,一旦确认传输数据完毕就会将回复报文的FIN字段置1,并产生随机seq序列号。
- 服务端收到客户端的TCP断开请求后,会回复客户端的断开请求,包含随机生成的seq字段和ACK字段,ACK字段会在客户端的TCP断开请求的seq基础上加1,从而完成客户端请求的验证回复。
- 至此TCP断开的4次挥手过程完毕!
断开过程状态机转变:
由于TCP连接是全双工的,断开连接会比建立连接麻烦一点点。
- 服务端先向客户端发送FIN报文,请求断开连接,其状态变为
FIN_WAIT1
。 - 客户端收到FIN后向服务端发送ACK,客户端状态变为
CLOSE_WAIT
。 - 服务端收到ACK后就进入
FIN_WAIT2
状态。此时连接已经断开了一半了。如果客户端还有数据要发送给服务端,就会继续发送。 - 直到发完了,就发送FIN报文,此时客户端会进入
LAST_ACK
状态。 - 服务端收到客户端的FIN后,会马上发送ACK给客户端,此时服务端进入
TIME_WAIT
状态 - 再过了
2MSL
长的时间后服务端进入CLOSED
状态。客户端收到服务端的ACK后也进入CLOSED
状态。 - 至此,还有一个状态没有提及:
CLOSING
状态。
CLOSING 状态表示:
- 客户端发送了FIN,但没有收到服务器的ACK,却收到了服务器的FIN。这种情况发生在服务器发送的ACK丢包的时候,因为网络传输有时会有意外发生。
由于断开过程中会有数据传输,故在tcpdump -c
指定抓包次数的时候值给大点,不然抓不到FIN断开的包。
看Flags标识:
- 10.0.0.77 > 10.0.0.1:Flags为[
F.
],此为10.0.0.77向10.0.0.1发送的断开FIN请求,和ack确认 - 10.0.0.1 > 10.0.0.77:Flags为[
.
],10.0.0.1先发送ack确认 - 10.0.0.1 > 10.0.0.77:Flags为[
F.
],10.0.0.1发送FIN确认和ack确认 - 10.0.0.77 > 10.0.0.1:Flags为[
.
],10.0.0.77发送ack确认,然后连接成功断开