TCP的三次握手和四次挥手
1. TCP的三次握手
TCP是面向连接的,也就是说它在通信时,会发送请求到一个确切的地址,在双方握手之后,会在两个应用程序之间建立一个全双工的通信,占用两个计算机之间的通信线路,直到有一方关闭为止。
TCP可靠性的含义是:接收方收到的数据是完整, 有序, 无差错的
先修知识:TCP报文格式:
1.1 三次握手的过程
1⃣️客户端发送SYN连接请求(同步标志位SYN=1,随机产生一个序号seq=X)的报文发送给服务器端,进入syn_send状态(TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。这个三次握手中的开始。表示客户端想要和服务端建立连接。)
p.s.第一次握手客户端发送的报文如下:
2⃣️服务器端收到连接请求,由同步标志位SYN=1知道客户端想要建立连接,将确认报文中中同步标志位SYN置1,确认标志位ACK置1,同时随机初始一个序号seq=Y,确认号ack=X+1,服务器端进入SYN_RCVD状态
p.s.第二次握手服务器端发出的报文如下:
3⃣️客户端收到后,确认服务器发送的报文中是否标志位ACK=1,确认号ack=X+1,如果正确,就把标志位ACK置1,确认号ack=Y+1,并在数据段放入ISN+1,发送给服务器端,客户端和服务器进入ESTABLISHED状态,完成三次握手,客户端与服务器开始传送数据。
第三次握手客户端发送的报文:
1.2 为什么不能两次握手或者四次握手?
两次握手=>客户端只能知道自己发出的请求服务器端收到了,服务器端不知道服务器端发给客户端发的信息客户端能不能收到。
四次握手=>客户端和服务器端均已知能互相通信,如果再发送确认信息,就是浪费资源。
2.四次挥手
2.1 四次挥手的过程
1⃣️客户端发送结束标志FIN,进入FIN_WAIT1状态
e.g. 客户端说"我没有数据要发给你了,我说完了(FIN)"
=>客户端:FIN_WAIT1
2⃣️服务器端接收到FIN后,发送一个ACK,确认序号ack为上一次传输数据收到的序号+1,服务器端进入CLOSE_WAIT状态,客户端进入FIN_WAIT2状态(FIN_WAIT2状态是在主动断开的一端FIN请求发出且收到对应的ACK后进入的)。
e.g. 服务器端说“你的请求我收到了(ACK),你等等,我还没准备好”
=>客户端:FIN_WAIT2,服务器端:CLOSE_WAIT
p.p.s. 如果服务器发送数据,客户端依然要接受
3⃣️服务器端关闭与客户端的连接,发送结束标志FIN给客户端,进入LAST_ACK状态
e.g. 服务器端说“好了,我数据发完了,准备关连接了”
=>服务器端:LAST_ACK
4⃣️客户端收到FIN后,发送一个ACK给服务器端,客户端进入TIME_WAIT状态,这时,内核会设置一个时间长度为 2MSL 的定时器,当定时器在到时间点后,客户端进入CLOSED状态。服务器端在收到ACK后,进入CLOSED状态,四次挥手完成。
e.g. 客户端说“我知道了(ACK)”==>客户端:TIME_WAIT
服务器端收到ACK==>服务器端:CLOSED
客户端等了2MSL没有收到回复,证明服务器端正常关闭==>客户端:CLOSED
注:MSL(最大分段生存期)指明TCP报文在Internet上最长生存时间,每个具体的TCP实现都必须选择一个确定的MSL值。TIME_WAIT 状态最大保持时间是2 * MSL,一般MSL的时间为30s,1min,2min
2.2 为啥在TIME_WAIT后还要再等待2MSL才能进入CLOSED状态?
虽然双方都同意关闭了连接,但是假设网络不可靠,客户端无法保证自己发送给服务器端的ACK报文服务器端一定会收到(比如超时了,如果因为超时导致服务器端未收到ACK报文而重发FIN报文,那就需要客户端重发丢失的ACK报文)
2.3 为什么连接是三次握手断开是四次挥手?
因为在三次握手阶段SYN和ACK可以放在一个报文里传送,但四次挥手时,收到对方的FIN报文通知只能表示对方没有数据要传送给你了,但是你的数据未必全都发送给了对方,所以需要发送一些数据给对方之后(?????)再发送FIN报文表示你同意关闭连接(ACK和FIN分开发送)
3. 三次握手和四次挥手过程中客户端和服务器端的状态变化图
REFERENCE:
TCP协议详解
网络学习-传输层TCP协议(确认应答与超时重发)
【TCP协议】(2)—TCP三次握手和四次挥手
TCP三次握手四次挥手详解
浅谈 TCP 四次挥手
TCP的三次握手与四次挥手理解及面试题(很全面)