通过一些问题来讨论 TCP 协议中的三次握手机制
- 说一下三次握手的大致过程?
- 为什么需要三次握手?2 次不可以吗?
- 第三次握手,可以携带数据吗?第二次呢?
- 三次握手连接阶段,最后一次ACK包丢失,会发生什么?
1. 说一下三次握手的大致过程
客户端在与服务器建立 TCP 连接时首先会进行三次握手。
第一次握手:客户端给服务端发送一个 SYN 报文,并指明客户端的初始化序列号 ISN,此时客户端处于 SYN_SEND 状态
第二次握手:服务器收到客户端的 SYN 报文后,会以自己的 SYN 报文作为应答,同时也指定了自己的 ISN,并把客户端发来的 ISN + 1 作为 ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_RCVD 状态
第三次握手:客户端收到 SYN 报文后,会将服务器发来的 ISN + 1 作为 ACK 报文发出,表示已经收到了服务端的 SYN 报文,此时客户端处于 ESTABLISHED 状态
最后服务器收到 ACK 报文之后,也会处于 ESTABLISHED 状态,到这里,双方的连接就建立好了
第一次客户端发送 SYN 包,证明自身发送能力正常
第二次服务端发送 SYN + ACK 包,证明自身发送能力和接受能力正常
第三次客户端发送 ACK 包,证明自身接受能力正常
2. 为什么需要三次握手?2 次不可以吗?
为什么 2次不可以,主要原因就是不可靠
第一是可能会有已经失效的连接请求报文传送到服务端,引起连接错误
因为路径堵塞或者其他原因,客户端发送的请求报文可能要很久才能到服务端。在一定时间内,如果客户端没有收到来自服务端的回应报文,就会重新发送一份请求报文。这次报文很顺利地到达服务端,不过紧接着,第一次发送的请求报文也来到了服务端,这个请求报文已经失效了。如果是二次握手建立连接的话,服务端接收到这个失效的请求报文后,就会建立连接,从而导致错误。
第二是服务端在正确收到客户端的请求报文后,不能确定自己给客户端发送的响应报文,对方是否收到(如网络丢包)
导致服务端在等着客户端发送数据,而客户端等着服务端返回响应
那 4 次握手行吗?
可以但没必要,三次握手已经确认了建立连接需要的信息了,第四次握手不会带来新的信息,只能使得这个过程更加冗余。
3. 第三次握手,可以携带数据吗?第二次呢?
这个问题 RFC 文档中提到过,第三次握手时,客户端向服务端返回的报文中可以携带数据,即使此时服务端是 SYN_REVEIVED 状态,但由于数据报中也带有 ACK 的值,服务端接受之后会先确定这个 ACK,然后建立连接,进入 ESTABLISHED 状态,之后就能正常接受这个数据包了
但需要多注意的是,一般情况下第三次握手的报文中是不会携带数据的,大多数情况都是客户端在发生第三次握手的报文之后,不等服务端先接受,就接着发送正常通信的数据包。服务端先接受到第三次握手包之后建立连接,接着正常接受数据包。但假如由于网络原因,客户端发送的第三次握手包丢失了,但接着发送的数据包正常被服务端接收,由于这个数据包也带有 ACK 的值,服务端就会把这个数据包当作第三次握手包,先建立连接再正常读取数据。至于真正的第三次握手包,如果是丢失了的话就丢失吧,没影响。如果由于网络原因而比数据包后到达,服务端会直接忽略
TCP 的第一二次握手,都是不可以携带数据的。第一次握手不能的原因是防止恶意的握手请求。第二次不能是因为此时服务端只确认了客户端的 “发生能力正常”,却不知道接受能力是否正常,所以还不能携带数据
4. 三次握手连接阶段,最后一次ACK包丢失,会发生什么?
这个需要分情况看,第三次握手的 ACK 包丢失后,客户端有没有继续发送带有 ACK 的数据包,如果有,还是可以建立连接的。
如果没有,也就是服务端此时迟迟接收不到来自客户端的 ACK,那么站在服务端的视角,有可能是第二次握手时给客户端的 SYN + ACK 包丢失,也有可能是客户端第三次握手的 ACK 包丢失。不管哪种情况,服务端此时只需重新进行第二次握手。也就是发送客户端一份新的 SYN + ACK 包即可,客户端收到后也会重新发送一份 ACK 报文,建立连接
诚恳欢迎大家提出意见
......(未完待续