第一次握手:建立连接时,客户端发送syn
包(syn=x)到服务器,并进入SYN_SEND状态,等待服务器确认;SYN(Synchronize Sequence Numbers):同步序列编号。
第二次握手:服务器收到syn
包,必须确认客户的SYN(ack = x + 1),同时自己也发送一个SYN包(SYN=y),即syn=y,即SYN+ACK
包,此时服务器进入SYN_RECV状态。
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送ACK包(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
三次握手的目的是建立可靠的通信信道,简单来说就是数据的发送与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的。
只有经历三次握手才能确认双方的收发功能都正常,缺一不可:
第一次握手(客户端发送 SYN 报文给服务器,服务器接收该报文):客户端什么都不能确认;服务器确认了对方发送正常,自己接收正常
第二次握手(服务器响应 SYN 报文给客户端,客户端接收该报文):
客户端确认了:自己发送、接收正常,对方发送、接收正常;
服务器确认了:对方发送正常,自己接收正常
第三次握手(客户端发送 ACK 报文给服务器):
客户端确认了:自己发送、接收正常,对方发送、接收正常;
服务器确认了:自己发送、接收正常,对方发送、接收正常
服务器发送完 SYN-ACK 包,如果未收到客户端响应的确认包,也即第三次握手丢失。那么服务器就会进行首次重传,若等待一段时间仍未收到客户确认包,就进行第二次重传。如果重传次数超过系统规定的最大重传次数,则系统将该连接信息从半连接队列中删除。
注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s…
第一次挥手:客户端发送一个FIN
报文(请求连接种植:FIN=1
),报文中会指定一个序列号seq=u
,并且停止再发送数据,主动关闭TCP
连接。此时客户端处于FIN_WAIT1
状态,等待服务端的确认。
FIN-WAIT1
等待远程TCP的连接中断请求,或先前的连接中断请求的确认。
第二次挥手:服务端收到FIN之后,会发送ACK报文,且把客户端的序号值+1作为ACK报文的序列号值,表明已经收到客户端的报文了,此时服务端处于CLOSE_WAIT状态
CLOSE-WAIT
等待从本地用户发来的连接中断请求。
此时TCP处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2
(终止等待2)状态,等待服务端发出的连接释放报文段。
FIN-WAIT-2
从远程TCP等待连接中断请求;
第三次挥手:如果服务端也想断开连接了(没有要向客户端发出的数据),和客户端的第一次挥手一样,发送FIN
报文,且指定一个序列号。此时服务端处于LAST_ACK
状态,等待客户端的确认。
LAST-ACK
等待原来发向远程TCP
的连接中断请求的确认。
第四次挥手:客户端收到FIN
之后,一样发送一个ACK
报文作为应答(ack = w + 1),且把服务器的序列值+1作为自己ACK
报文的序号值(seq = u + 1),此时客户端处于TIME_WAIT
(时间等待)状态。
TIME-WAIT
等待足够的时间以确保远程TCP
接收到连接中断请求的确认。
由于 TCP 的半关闭(half-close)特性,TCP 提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
任何一方都可以在数据传送结束后发出连接释放的通知,待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后就完全关闭了TCP连接。
通俗的来说,两次握手就可以释放一端到另一端的 TCP 连接,完全释放连接一共需要四次握手。
举个例子:A 和 B 打电话,通话即将结束后,A 说 “我没啥要说的了”,B 回答 “我知道了”,于是 A 向 B 的连接释放了。但是 B 可能还会有要说的话,于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了”,A 回答“知道了”,于是 B 向 A 的连接释放了,这样整个通话就结束了。