本篇文章已同步更新至github仓库JavaSummary,欢迎star!
1. TCP三次握手
1.1 TCP三次握手过程
最开始双方都处于CLOSED
状态。然后服务端开始监听某个端口,进入了LISTEN
状态
第一次握手:客户端主动发起连接,发送 SYN
, 自己变成了SYN-SENT
状态
第二次握手:服务端接收到,返回SYN
和ACK
(对应客户端发来的SYN),自己变成了SYN-REVD
第三次握手:客户端再发送ACK
给服务端,自己变成了ESTABLISHED
状态;服务端收到ACK
之后,也变成了ESTABLISHED
状态
凡是需要对端确认的,一定消耗TCP报文的序列号
SYN
需要对端的确认, 而ACK
并不需要,因此SYN
消耗一个序列号而ACK
不需要
1.2 为什么TCP建立连接需要三次握手
- TCP作为一种可靠传输控制协议,其核心思想:既要保证数据可靠传输,又要提高传输的效率,而用三次恰恰可以满足以上两方面的需求
- TCP连接三次握手的目的:
- 确认双方的发送和接收能力正常
- 确认通信双方数据原点的序列号(Initial Sequence Number,32位长,由操作系统动态随机选取),序列号就是给数据字节流进行编号
- 通信双方分别以该序列号为原点,对自己将要发送的每个字节的数据进行编号,以便对方可以确认对方发送的每一个字节
1.2.1 握手为什么不是两次?
-
根本原因: 无法确认客户端的接收能力
- 第一次握手:客户端什么也确认不了,服务端可以确认客户端的发送能力和自己的接收能力
- 第二次握手:客户端可以确认自己的发送和接收能力以及服务端的发送和接收能力
- 第三次握手:服务端可以确认自己的发送能力和客户端的接收能力
-
假设握手两次就可以建立连接,此时已失效的连接请求报文段如果突然又传送到了服务端,就会产生错误
- "已失效的连接请求报文段"产生在这样一种情况下:
- 客户端发送了
SYN
报文想握手,但是这个包滞留在了网络中的某个节点迟迟没有到达,客户端以后是丢了包,于是重传SYN
,服务端收到后然后返回SYN+ACK
,两次握手建立好了连接 - 看似没有问题,但是连接关闭后,如果之前滞留在网络中的
SYN
报文段到达了服务端,这时候由于是两次握手,服务端只要接收到然后发送相应的数据包,就默认建立连接,但是现在客户端已经断开了,服务端却以为新的连接已经建立,并一直等待客户端发送数据,这样就带来了连接资源的浪费 - 采用"三次握手"的办法就可以防止上述现象发生
- 客户端发送了
- "已失效的连接请求报文段"产生在这样一种情况下:
1.2.2 握手为什么不是四次?
- 三次握