首先要明白两次握手是必须的,如果只有一次握手,无法建立可靠的连接,因为并不知道另一方有没有收到信息,所以两次握手是必须的。
1.第一次握手
:客户端向服务器发送请求,服务器接收到请求
客户端 ——> 服务端 : SYN = 1 , seq = x
SYN = 1 代表同步请求,seq则是发送的序列号(必须发送序列号,因为序列号可以避免因网络延迟带来的信号混乱)
2.第二次握手
:服务器接受请求,向客户端发送同步信号
服务端 ——> 客户端: SYN = 1, ACK = 1, seq = y, ack = x + 1
SYN = 1 代表同步请求,seq代表服务端发出报文段的序列号,ack则是确认号(确认号只有在 ACK = 1 的情况下才有效).
SYN = 1 , ACK = 1代表这是对客户端发来的同步请求的回复
3.第三次握手
:客户端向服务器发送准备完成信号
客户端 ——> 服务端: ACK = 1, seq = x + 1 , ack = y + 1
此时的 SYN = 0, 说明此信号已经不是同步请求,而是互相传送数据的确认,第三次握手可以避免因网络延时问题造成的服务器空等待,也可以避免第二次握手信号丢失导致服务器错误传输数据。
TCP关闭连接必须是可靠的,也就是让客户端和服务端都可靠的关闭连接。
如果只有一次挥手
客户端就直接关闭,那么可能数据还没有传输完成,服务器还有可能空等待。
如果是两次挥手
,数据也可能没有传完。
如果是三次挥手
,这一次的挥手可能丢失,这样服务器虽然正常关闭,但是客户
端却一直空等待,认为服务器还在传数据。
第四次挥手
:可以防止第三次挥手的信号丢失
等待2ML
:客户端第四次挥手后等待2MSL, 可以防止第四次挥手信号的丢失
四次挥手分析:
1.第一次挥手
:客户端告知服务器,自己传输完成,让服务器关闭
客户端 ——> 服务端: seq = u, FIN = 1
2.第二次挥手
:服务器得知客户端将结束连接,返回确认消息,并持续传送最后的数据
服务端 ——> 客户端: seq = v, ACK = 1, ack = u + 1
3.第三次挥手
:服务器将最后的数据传送完成,向客户端发送确认消息,让客户端关闭
服务端 ——> 客户端: seq = w, FIN = 1, ACK = 1, ack = u + 1
4.第四次挥手
:客户端收到消息,等待2MSL之后,如果没有服务端重发的ACK消息,自己就关闭
客户端 ——> 服务端: seq = u + 1, ACK = 1, ack = w + 1
TCP的四次挥手在本质上都是为了让客户端与服务器正常的关闭。
那么为什么客户端需要等待2MSL再关闭
?
因为服务端可能没有收到最后一次发来的ACK,那么他就不会关闭,这样客户端提前关闭了,服务端却一直再运行消耗着资源。
让客户端等待2MSL再关闭,如果期间服务端没有收到最后一次发来的ACK,那么会有超时重传机制,也就是相当于重新进行第三次挥手,那么客户端在2MSL的时间内也回重新收到ACK,然后再一次进行第四次挥手让服务器关闭
注意:服务端在进行第三次挥手后,立刻会启动超时重传机制;客户端在发出第四次挥手后,立刻就会启动2MSL的等待
1.为什么连接的时候是三次握手,关闭的时候却是四次握手?(为什么挥手需要四次?
根本原因是因为服务器在接收到客户端的FIN请求后,会进行最后数据的传输;如果没有数据要传输,改成三次挥手也可以。
2.为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
如果没有TIME_WAIT,可能会出现下面两种情况:
1.第四次挥手ACK信号丢失,客户端直接进入CLOSED状态,服务端将会一直等待;让客户端等待2MSL时间,即便是第四次挥手信号丢失,服务端也会开启超时重传机制,重新发送第三次挥手的信号(2MSL的时间可以让信号丢失的情况下,超时重传机制重新发的信号也能够到达)。
2.因网络延迟在传输过程中迟到的数据在TIME_WAIT状态被直接忽略,这样不会对下一次的连接造成影响。
3.为什么不能用两次握手进行连接?
如果只有两次握手,可能会有两种情况:
1.如果第二次握手的ACK信号丢失,服务器直接进入ESTABLISHED状态,而客户端没有收到,会形成死锁;
2.因网络延迟发生的串链现象,客户端的SYN请求延后到达,已经失效但是服务器也回应答,造成死锁
4.如果已经建立了连接,但是客户端突然出现故障了怎么办?
服务端会有一个超时关闭机制,如果限定时间内没有接收到客户端的数据传送,那么就认为客户端已经出现故障, 服务器自动断开