image.png
TCP 提供面向有连接的通信传输。面向有连接是指在数据通信开始之前先做好两端之间 的准备工作。
所谓三次握手是指建立一个 TCP 连接时需要客户端和服务器端总共发送三个包以确认 连接的建立。在 socket 编程中,这一过程由客户端执行 connect 来触发。
第一次握手:客户端将标志位 SYN 置为 1,随机产生一个值 seq=J,并将该数据包发送给服务器端,客户端进入 SYN_SENT 状态,等待服务器端确认。
第二次握手:服务器端收到数据包后由标志位 SYN=1 知道客户端请求建立连接,服务器端将标志位 SYN 和 ACK 都置为 1,ack=J+1,随机产生一个值 seq=K,并将该数据包发送给 客户端以确认连接请求,服务器端进入 SYN_RCVD 状态。
第三次握手:客户端收到确认后,检查 ack 是否为 J+1,ACK 是否为 1,如果正确则将 标志位 ACK 置为 1,ack=K+1,并将该数据包发送给服务器端,服务器端检查 ack 是否为 K+1, ACK 是否为 1,如果正确则连接建立成功,客户端和服务器端进入 ESTABLISHED 状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。 (第三次是否含有seq取决于第三次是否携带了数据信息,不过不携带数据就没有seq)

为什么 TCP 握手需要三次?

TCP 是可靠的传输控制协议,而三次握手是保证数据可靠传输又能提高传输效率的最小次数。为什么?RFC793,也就是 TCP 的协议 RFC 中就谈到了原因,这是因为:
为了实现可靠数据传输, TCP 协议的通信双方,都必须维护一个序列号, 以标识发送出去的数据包中,哪些是已经被对方收到的。
举例说明:发送方在发送数据包(假设大小为 10 byte)时, 同时送上一个序号( 假设 为 500),那么接收方收到这个数据包以后, 就可以回复一个确认号(510 = 500 + 10) 告 诉发送方 “我已经收到了你的数据包, 你可以发送下一个数据包, 序号从 511 开始” 。 三次握手的过程即是通信双方相互告知序列号起始值,并确认对方已经收到了序列号 起始值的必经步骤。
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。
至于为什么不是四次,很明显,三次握手后,通信的双方都已经知道了对方序列号起始 值,也确认了对方知道自己序列号起始值,第四次握手已经毫无必要了。