握手和挥手的话题恒古不变,笔者看完链路帧、IP数据报、TCP/UDP的具体格式才对其有了较良好的理解,学习果然要注重基础
1. 前提
此笔记默认已经熟悉TCP协议头的首部格式了,因为握手和挥手是建立的TCP协议上的,具体来说是建立在其内部的各种字段上
图出自《图解TCP/IP》
SYN:请求建立连接,初始化随机序列号,其ACK为0(其余情况ACK都为1)
FIN:希望断开连接
ACK:大写表示控制位
ack:确认应答号,表示下次该收到的数据序列号
seq:序列号
2. 三次握手
第一次:
Client:发送SYN包(SYN=1,ACK=0,seq=客户端随机),并进入SYN-SENT 状态
Server:收到SYN=1后知道Client要请求连接
第二次:
Server:返回应答报文ACK(ack=对方的seq+1)
Server:发送SYN包(SYN=1,ACK=1,seq=服务器随机)
以上两步骤合并起一步发送,然后进入SYN-RCVD 状态
第三次:
Client:验证对方ack,然后返回应答报文ACK(ack= 对方seq+1),且可携带数据,前两次不可
Server:验证对方ack,ACK是否=1,建立连接
以上两步分别都进入ESTABLISHED 状态
2.2 为什么是三次握手不是二次或四次
原因一:防止失效的请求连接报文传到服务器
假设两次握手的情况:Client第一次发送连接请求因网络延迟没有到达服务器,被认为失效,
然后Client第二次发送请求,这时成功两次握手并建立连接(假设情况),数据传送完毕断开连接。
此时第一次发送的请求连接这时才到达服务器,服务器收到请求后因为是两次握手,Server直接发送确认报文并建立连接,但此刻Client并没有请求所以不响应,导致资源白白浪费
原因二:三次握手才能确保双方序列号被同步
第一次客户端发送自己的随机序列号,第二次服务端确认应答,第三次服务器将自己的随机序列号发送给客户端,第四次客户端确认应答表示收到。由于第二三次可以合并,所以成为了三次握手不是四次
3. 四次挥手
第一次:
Client:发送FIN包,并进入FIN_WAIT_1状态
第二次:
Server:接收FIN包后,就向客户端发送ACK应答报文,并进入CLOSED_WAIT状态
Client:收到服务端的ACK应答报文后,之后进入FIN_WAIT_2状态。
第三次:
Server:处理完数据后,也向客户端发送FIN包,并进入LAST_ACK状态
第四次:
Client:收到FIN报文,回应ACK应答报文,进入TIME_WAIT状态
Client:经过2MSL时间后,自动进入CLOSE状态,完成连接的关闭
Server:服务器收到了 ACK应答报文后,就进入了CLOSE状态,完成连接的关闭
注意:主动关闭连接的,才有 TIME_WAIT 状态
注意:MSL是报文最大生存时间,TTL是IP数据报最大经过路由数,而MSL大于等于 TTL消耗为0的时间
3.1 为什么需要四次
Client请求关闭仅表示自己不会发送数据,Server数据可能还没发完,所以得先发送应答,等数据传完了再发送关闭请求。客户端请求FIN,服务端确认应答、服务端发送FIN,客户端确认应答。一来一回四次(与握手不同第二三次是分开的)
3.2 为什么主动关闭端需要等待2MSL
MSL是报文最大生存时间,是从客户端接收到 FIN 后发送 ACK 开始计时的:客户端需要保证最后一次发送的ACK报文到服务器,如果服务器未收到会重发FIN包,这样客户端还有时间再发ACK确认应答,重启2MSL计时。
3.3 TIME-WAIT状态其存在的原因
其一:保证「被动关闭连接」的一方能被正确的关闭,即保证最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭
其二:防止已失效的连接请求报文段出现在本连接中。
假如客户端发送关闭连接包FIN前服务器有个数据包被延迟了,此时连接已经关闭,然后有个新的连接重新开启,端口等一样则被复用,这次被延迟的数据才到达则会二者不同连接被混乱。出现了TIME-WAIT足以让两个方向上的数据包都被丢弃,则原连接的数据包在网络中都自然消失了,再出现的数据包一定都是新建立连接所产生的