这两天又复习了一下网络协议相关的知识,虽然一直在用,也明白原理,但是每次回顾的时候都会有新的体会。我把之前总结的TCP三次握手和四次挥手的相关笔记又重新梳理并改正了一下。
建立TCP需要三次握手才能建立,而断开连接则需要四次握手。整个过程如下图所示:
【注意1】
上图中的每一个箭头都代表着一次 TCP数据包的发送。
需要注意的是,上图中出现的 ACK = x +1 的写法很容易让人误以为数据包中的 ACK 域的数据值被填成了 y+1 。 ACK = x+1 的实际含义是:
- TCP 包的 ACK 标志位(1 bit) 被置成了 1
- TCP 包的确认号(acknowledgement number ) 的值为 x+1
所以可以理解为 ACK=1, ack=x+1。
类似的, TCP 数据包中的 SYN 标志位, 也容易与序号(sequence number) 混淆(SYN=1, seq=x), 这点需要注意
建立连接:
-
第一次握手:
A想要和B建立连接,随机生成数据序列号seq(例如x),以及将SYN设置为1发送给B。
(A->SYN_SEND) -
第二次握手:
B收到A的连接请求后会发回确认包应答,即SYN和ACK标志位都设置为1,并将确认序列号ack设置为x+1,以及B端自己生成的数据序列号seq(例如y)回发给A
(B->SYN_RCVD | A->ESTABLISHED) -
第三次握手:
A在收到B的确认应答包之后,会再次发送确认包,SYN设置为0,ACK设置为1,以及B发送过来的序列号+1(y+1)。
B->ESTABLISHED
【问题1】为什么需要握手的操作?
如果对比一下UDP协议会发现,UDP是没有握手操作的。
这里就可以看出TCP和UDP的一个本质的区别:TCP是可靠的通信传输协议,UDP则是不可靠的。
- TCP 的可靠性含义: 接收方收到的数据是完整, 有序, 无差错的。
- UDP 不可靠性含义: 接收方接收到的数据可能存在部分丢失, 顺序也不一定能保证。
两者都是基于IP协议实现的,但为什么TCP就是可靠的传输协议呢?
TCP为了实现可靠的数据传输,通信双方都需要确认自己发送的数据包确实被对方收到了,为了实现这种机制,出现了序号(sequence number 即上面说的seq)和确认号(acknowledgement number 即上面说的小写的ack)。
那么发送方在发送数据的同时还会带上一个自己随机生成的序号(比方说200),接收方在收到数据之后会回复一个确认号用来确认(201 = 200 + 1),表明:“我已经收到了你的数据包, 你可以发送下一个数据包, 序号从 201 开始”。
【问题2】为什么连接的时候是三次握手?
正如上文所说的,为了实现可靠传输,发送方和接收方始终需要同步( SYNchronize )序号。
需要注意的是, 序号并不是从 0 开始的, 而是由发送方随机选择的初始序列号 ( Initial Sequence Number, ISN )开始 。 由于 TCP 是一个双向通信协议, 通信双方都有能力发送信息, 并接收响应。 因此, 通信双方都需要随机产生一个初始的序列号, 并且把这个起始值告诉对方。
所以【问题2】的结论是:
为了实现可靠数据传输。
TCP 协议的通信双方, 都必须维护一个序列号(seq)用以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值,并确认对方已经收到了序列号起始值的必经步骤。
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。
断开连接:
那如何断开连接呢?简单的过程如下:
- 假设Client端发起中断连接请求,也就是发送FIN报文(第一次挥手)。
- Server端接到FIN报文后,意思是说:"我Client端没有数据要发给你了",但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据(第二次挥手)。
- 所以Server端先发送ACK告诉Client端:"你的请求我收到了,但是我还没准备好,请继续你等我的消息"。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。
- 当Server端确定数据已发送完成,则向Client端发送FIN报文告诉Client端:"好了,我这边数据发完了,准备好关闭连接了"(第三次挥手)**。
- Client端收到FIN报文后,"就知道可以关闭连接了,但是还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。"(第四次挥手)。
- Server端收到ACK后,"就知道可以断开连接了"于是断开连接。
- Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,Client端也可以关闭连接了。Ok,TCP连接就这样关闭了。
【注意2】中断连接端可以是Client端,也可以是Server端。
【注意3】在TIME_WAIT状态中,如果TCP client端最后一次发送的ACK丢失了,它将重新发送。TIME_WAIT状态中所需要的时间是依赖于实现方法的。典型的值为30秒、1分钟和2分钟。等待之后连接正式关闭,并且所有的资源(包括端口号)都被释放。
【问题3】为什么断开连接需要四次?
正如上面的所说,服务端需要确保数据传输完毕之后才能发FIN,在传输完毕之前需要先回复ACK给客户端,用来表明服务端收到了客户端的断开连接请求,稍后会再发送FIN
参考
https://blog.csdn.net/lengxiao1993/article/details/82771768
http://www.cnblogs.com/huhuuu/p/3572485.html
网友评论