1. 三次握手
SYN:同步
1.1 三次握手过程
- 服务端B都处于LISTEN(监听)状态,等待客户的连接请求。
- A向B发送连接请求报文,SYN = 1,ACK = 0,SEQ = x;
- B收到A的连接请求报文后,向B发出确认:SYN = 1,ACK = 1,SEQ = y,ack = x+1;
- A收到B的ACK报文后,再向B发出确认:SYN = 0;ACK = 1,SEQ =x + 1,ack = y+1;
- 连接建立,双方开始互相通信。
1.2 三次握手原因
参考:简书
一端(client)A发出去的第一个连接请求报文并没有丢失,而是因为某些未知的原因在某个网络节点上发生滞留,导致延迟到连接释放以后的某个时间才到达另一端(server)B。本来这是一个早已失效的报文段,但是B收到此失效的报文之后,会误认为是A再次发出的一个新的连接请求,于是B端就向A又发出确认报文,表示同意建立连接。如果不采用“三次握手”,那么只要B端发出确认报文就会认为新的连接已经建立了,但是A端并没有发出建立连接的请求,因此不会去向B端发送数据,B端没有收到数据就会一直等待,这样B端就会白白浪费掉很多资源。如果采用“三次握手”的话就不会出现这种情况,B端收到一个过时失效的报文段之后,向A端发出确认,此时A并没有要求建立连接,所以就不会向B端发送确认,这个时候B端也能够知道连接没有建立。
- A站:B站你好,我想和你建立客运线,请问你那边能为我腾一个车位出来吗(假设该信息被阻塞)(第一次握手)?
- A站(未能及时收到回信,重发):B站你好,我想和你建立客运线,请问你那边能为我腾一个车位出来吗(第一次握手)?
- B站(响应A重发的消息):好的,另外,你那边返程的车位准备好了吗(第二次握手)?
- A站:返程的车位准备好了(第三次握手)!
- 运行一段时间后,客运线关闭(假设是临时路线)
- 第一阶段丢失的那个信鸽此时将消息送到了,即:(B站你好,我想和你建立客运线,请问你那边能为我腾一个车位出来吗?)
- B站:好的,另外,你那边返程的车位准备好了吗(第二次握手)?
- 由于此时A站并不想建立到B站的线,所以忽略该信息。
- B站没有收到A站的回应,所以也不会完成客运线的建立。
2. 四次握手
2.1 四次握手的过程
参考:csdn博客
FIN:终止(finish)
- 客户端进程A发出连接释放报文,并停止发送数据,报文:FIN = 1,SEQ = u;此时客户端进入FIN-WAIT1状态:终止等待状态1。
- 服务端进程B收到连接释放报文,发出确认报文:ACK = 1,ack = u + 1,SEQ = v;此时服务端进入CLOSE-WAIT(关闭等待)状态。TCP连接处于半关闭状态:A不再向B发送数据,B仍然能向A发送数据。
- A收到B的确认后,进入FIN-WAIT2状态:终止等待状态2,等待B发送连接释放请求。
- B将最后的数据发送给A后,发送连接释放报文:FIN = 1,ACK = 1,ack = u + 1(B最后收到A的数据一直是u),SEQ = w,此时B进入LAST-ACK(最后确认)状态,等待A的最后确认。
- 客户端A收到连接释放报文后,发出确认报文:ACK = 1,ack = w+1,SEQ = u+1,此时,A进入TIME-WAIT(时间等待)状态。
- B收到A的确认报文后,进入CLOSED状态,双向连接都关闭。
2.2 四次握手的相关问题
- A最后为什么要进入TIME-WAIT状态,且TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
A需要确认最后的ACK报文到达B,如果最后的ACK报文丢失了,那么在TIME_WAIT期间内B就会再次发送FIN报文;如果ACK报文成功到达B,那么在TIME_WAIT期间内B就不会再次发送FIN报文,也就是A就能确保B收到了ACK,可以放心地进入CLOSED状态。 - 为什么连接建立时是三次,释放却是四次?
因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET(不能直接发送FIN+ACK),所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到Server端所有的报文都发送完了,再发送FIN报文,因此不能一起发送。故需要四步握手。