TCP三次握手和四次挥手
1 三次握手
1.1 基础知识
- SYN(SYNchronization):同步序号,用来建立连接。
SYN标志位和ACK标志位搭配使用,当SYN=1,ACK=0,表示连接请求;当SYN=1,ACK=1,表示连接被响应的时候;这个标志的数据包经常被用来进行端口扫描。 - ACK(ACKnowledgment):确认号,用于确认连接是否有效。
仅当ACK=1时确认号字段有效,当ACK=0时是无效的。TCP规定在连接建立后所有传送的报文段都必须把ACK置为1。 - ACKNum(Acknowledgment Number):所期望收到的下一个序列号。
32位确认序列号包含发送确认的一端所期望收到的下一个序号,因此,确认序号应当是上次已成功收到数据字节序号加1。不过,只有当标志位中的ACK标志(下面介绍)为1时该确认序列号的字段才有效。主要用来解决不丢包的问题; - seq(Sequence Number):序列号。
- FIN(finish):表示终结连接。
当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。
1.2 三次握手过程
- 第一次握手(SYN=1,ACK=0,seq=x)
客户端发送一个TCP的数据包(SYN=1,ACK=0)指明客户端打算连接服务器的端口,以及初始序号 X,保存在包头的序列号(Sequence Number)字段里。 - 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1)
服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 seq序列号,放到 Seq 域里,同时将确认序号(ACKNum)设置为客户的 seq加1,即X+1。 发送完毕后,服务器端进入SYN_RCVD
状态。 - 第三次握手(ACK=1,ACKnum=y+1)
客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写seq的+1发送完毕后,客户端进入ESTABLISHED
状态,当服务器端接收到这个包时,也进入ESTABLISHED
状态,TCP 握手结束。
完成了三次握手,客户端和服务器端就可以开始传送数据。
1.3 现实场景
客户端:“你好,在家不,有你的快递?”
服务端:“在的,送上来吧”
客户端:“好,这就给你送上来”
2 四次挥手
为了避免服务器与客户端双方的资源占用和损耗,当双方没有请求或响应传递时,任意一方都可以发起关闭请求。与创建TCP连接的3次握手类似,关闭TCP连接,需要4次握手。
TCP 的连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),也叫做改进的三次握手。客户端或服务器均可主动发起挥手动作,在 socket 编程中,任何一方执行 close()
操作即可产生挥手操作。
2.1 基础知识
- FIN_WAIT_1: 这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。(主动方)
- FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你(ACK信息),稍后再关闭连接。(主动方)
- CLOSE_WAIT:这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。(被动方)
- LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。(被动方)
- TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FINWAIT1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。(主动方)
- CLOSED: 表示连接中断。
2.2 四次挥手过程
- 第一次挥手(FIN=1,seq=x)
假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。发送完毕后,客户端进入FIN_WAIT_1
状态。 - 第二次挥手(ACK=1,ACKnum=x+1)
服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。发送完毕后,服务器端进入CLOSE_WAIT
状态,客户端接收到这个确认包之后,进入FIN_WAIT_2
状态,等待服务器端关闭连接。 - 第三次挥手(FIN=1,seq=y)
服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。发送完毕后,服务器端进入LAST_ACK
状态,等待来自客户端的最后一个ACK。 - 第四次挥手(ACK=1,ACKnum=y+1)
客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入TIME_WAIT
状态,等待可能出现的要求重传的 ACK 包。服务器端接收到这个确认包之后,关闭连接,进入CLOSED
状态。客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入CLOSED
状态。
2.3 现实场景
客户端:“兄弟,我这边没数据要传了,咱关闭连接吧。”
服务端:“收到,我看看我这边有木有数据了。”
服务端:“兄弟,我这边也没数据要传你了,咱可以关闭连接了。”
客户端:“好嘞。”