TCP(传输控制协议)是面向连接的协议,它通过三次握手(Three-Way Handshake)和四次挥手(Four-Way Handshake)来建立和关闭连接。
一、三次握手
三次握手的目的是确保客户端和服务器之间能够可靠地建立连接。在建立连接之前,双方的序列号和确认号要同步,保证数据传输的可靠性。
第一次握手:SYN
客户端发送一个SYN(同步序列号)包到服务器,告诉服务器它准备建立连接,并且初始化一个序列号(比如:seq = x)。
这个包中只含有SYN标志位,客户端处于SYN_SENT状态。
第二次握手:SYN-ACK
服务器收到客户端的SYN包后,回复一个SYN-ACK包,表示同意建立连接,并且服务器初始化一个序列号(比如:seq = y),同时确认客户端的序列号(ack = x + 1)。
服务器处于SYN-RECEIVED状态。
第三次握手:ACK
客户端收到服务器的SYN-ACK包后,发送一个ACK包确认连接的建立,客户端将确认号设置为ack = y + 1,并继续等待服务器的数据。
客户端和服务器都进入ESTABLISHED(已建立)状态,连接正式建立,数据可以开始传输了。
初始状态:客户端A和服务器B均处于CLOSED状态,然后服务器B创建socket,调用监听接口使得服务器处于LISTEN状态,等待客户端连接。(后续内容用A,B简称代替)
A首先向B发起连接,这时TCP头部中的SYN标识位值为1,然后选定一个初始序号seq=x(一般是随机的),消息发送后,A进入SYN_SENT状态,SYN=1的报文段不能携带数据,但要消耗一个序号。
B收到A的连接请求后,同意建立连接,向A发送确认数据,这时TCP头部中的SYN和ACK标识位值均为1,确认序号为ack=x+1,然后选定自己的初始序号seq=y(一般是随机的),确认消息发送后,B进入SYN_RCVD状态,与连接消息一样,这条消息也不能携带数据,同时消耗一个序号。
A收到B的确认消息后,需要给B回复确认数据,这时TCP头部中的ACK标识位值为1,确认序号是ack=y+1,自己的序号在连接请求的序号上加1,也就是seq=x+1,此时A进入ESTABLISHED状态,当B收到A的确认回复后,B也进入ESTABLISHED状态,至此TCP成功建立连接,A和B之间就可以通过这个连接互相发送数据了。
二、四次挥手
四次挥手的目的是为了确保双方都完成数据传输,并且没有数据丢失,保证连接的可靠关闭。
第一次挥手:FIN
客户端向服务器发送一个FIN包,表示客户端没有数据发送了,准备关闭连接(seq = a)。
客户端进入FIN_WAIT_1状态。
第二次挥手:ACK
服务器收到FIN包后,回复一个ACK包,确认客户端的关闭请求(ack = a + 1),并进入CLOSE_WAIT状态。
服务器可以继续向客户端发送剩余的数据,直到完全完成数据传输。
第三次挥手:FIN
当服务器的数据发送完毕,服务器向客户端发送一个FIN包,表示服务器也没有数据发送了,准备关闭连接(seq = b)。
服务器进入LAST_ACK状态。
第四次挥手:ACK
客户端收到服务器的FIN包后,回复一个ACK包,确认服务器的关闭请求(ack = b + 1)。
客户端进入TIME_WAIT状态,等待足够的时间,以确保服务器收到最后的ACK包。
服务器收到ACK包后,进入CLOSED状态,连接完全关闭。
客户端的TIME_WAIT状态一般会持续2倍的MSL(Maximum Segment Lifetime,最大报文生存时间),此时如果有数据包丢失,客户端可以重新发送ACK包。最终,客户端也进入CLOSED状态,连接完全断开。
初始状态:客户端A和服务器B之间已经建立了TCP连接,并且数据发送完成,打算断开连接,此时客户端A和服务器B是等价的,双方都可以发送断开请求,下面以客户端A主动发起断开请求为例。(后续内容用A,B简称代替)
A首先向B发送断开连接消息,这时TCP头部中的FIN标识位值为1,序号是seq=m,m为A前面正常发送数据最后一个字节序号加1得到的,消息发送后A进入FIN_WAIT_1状态,FIN=1的报文段不能携带数据,但要消耗一个序号。
B收到A的断开连接请求需要发出确认消息,这时TCP头部中的ACK标识位值为1,确认号为ack=m+1,而自己的序号为seq=n, n为B前面正常发送数据最后一个字节序号加1得到的,然后B进入CLOSE_WAIT状态,此时就关闭了A到B的连接,A无法再给B发数据,但是B仍然可以给A发数据(此处存疑),同时B端通知上方应用层,处理完成后被动关闭连接。然后A收到B的确认信息后,就进入了FIN_WAIT_2状态。
B端应用层处理完数据后,通知关闭连接,B向A发送关闭连接的消息,这时TCP头部中的FIN和ACK标识位值均为1,确认号ack=m+1,自己的序号为seq=k,(B发出确认消息后有发送了一段数据,此处存疑),消息发送后B进入LAST_ACK状态。
A收到B的断开连接的消息后,需要发送确认消息,这是这时TCP头部中的ACK标识位值为1,确认号ack=k+1,序号为m+1(因为A向B发送断开连接的消息时消耗了一个消息号),然后A进入TIME_WAIT状态,若等待时间经过2MSL后,没有收到B的重传请求,则表明B收到了自己的确认,A进入CLOSED状态,B收到A的确认消息后则直接进入CLOSED状态。至此TCP成功断开连接。
【注意】
在连接和断开的过程都有提到ACK和ack,这一点要注意区分,大写的ACK代表TCP头部中6个标识位之一,是表明这是个确认报文,而小写的ack表示确认序号,表明对方发来的数据到ack这个序号前的都已经收到了。
三、为什么要三次握手?
如果只有一次握手,Client不能确定与Server的单向连接,更加不能确定Server与Client的单向连接;
如果只有两次握手,Client确定与Server的单向连接,但是Server不能确定与Client的单向连接;
只有三次握手,Client与Server才能相互确认双向连接,实现双工数据传输。
四、为什么要四次挥手?
“三次握手”的第二次握手发送SYN+ACK回应第一次握手的SYN,但是“四次挥手”的第二次挥手只能发送ACK回应第一次挥手的FIN,因为此时Server可能还有数据传输给Client,所以Server传输数据完成后才能发起第三次挥手发送FIN给Client,等待Client的第四次挥手ACK。
TCP四次挥手 TIME_WAIT出现在哪 为什么要有TIME_WAIT:
第四次挥手,这段等待时间就是为了在B没收到确认消息时,接收B的重传请求的。