讲一下TCP三次握手、四次挥手过程及原理
什么是TCP?
TCP 提供面向有连接的通信传输,面向有连接是指在传送数据之前必须先建立连接,数据传送完成后要释放连接。
无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。
同时由于TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,TCP是全双工模式,所以需要四次挥手关闭连接。
TCP 包头格式
图片来源网络

TCP首部承载这TCP协议需要的各项信息,下面我们来分析一下:
-
TCP端口号
TCP的连接是需要四个要素确定唯一一个连接:(源IP,源端口号)+ (目的IP,目的端口号)
所以TCP首部预留了两个 16 位作为端口号的存储,而IP地址由上一层IP协议负责传递。
源端口号和目地端口各占 16 位两个字节,也就是端口的范围是2^16=65535
-
TCP的序号和确认号- 32 位序号
seqSequence number缩写seq,TCP通信过程中某一个传输方向上的字节流的每个字节的序号,通过这个来确认发送的数据有序,比如现在序列号为 1000,发送了 1000,下一个序列号就是 2000。 - 32 位确认号
ackAcknowledge number缩写ack,TCP对上一次seq序号做出的确认号,用来响应TCP报文段,给收到的TCP报文段的序号seq加 1。
- 32 位序号
-
TCP的标志位 每个TCP段都有一个目的,这是借助于 TCP 标志位选项来确定的,允许发送方或接收方指定哪些标志应该被使用,以便段被另一端正确处理。用的最广泛的标志是
SYN,ACK和FIN,用于建立连接,确认成功的段传输,最后终止连接。-
SYN:简写为 S,同步标志位,用于建立会话连接,同步序列号; -
ACK: 简写为.,确认标志位,对已接收的数据包进行确认; -
FIN: 简写为 F,完成标志位,表示我已经没有数据要发送了,即将关闭连接; -
PSH:简写为 P,推送标志位,表示该数据包被对方接收后应立即交给上层应用,而不在缓冲区排队; -
RST:简写为 R,重置标志位,用于连接复位、拒绝错误和非法的数据包; -
URG:简写为 U,紧急标志位,表示数据包的紧急指针域有效,用来保证连接不被阻断,并督促中间设备尽快处理;
-
TCP 三次握手和四次挥手
三次握手
图片来源网络

- 第一次握手:客户端将
TCP报文标志位SYN置为 1,随机产生一个序号值 seq=J,保存在TCP首部的序列号(Sequence Number)字段里,指明客户端打算连接的服务器的端口,并将该数据包发送给服务器端,发送完毕后,客户端进入SYN_SENT状态,等待服务器端确认。 - 第二次握手:服务器端收到数据包后由标志位
SYN=1知道客户端请求建立连接,服务器端将TCP报文标志位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状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。
注意:我们上面写的 ack 和 ACK,不是同一个概念:
- 小写的
ack代表的是头部的确认号Acknowledge number, 缩写ack,是对上一个包的序号进行确认的号,ack=seq+1。 - 大写的
ACK,则是我们上面说的TCP首部的标志位,用于标志的TCP包是否对上一个包进行了确认操作,如果确认了,则把ACK标志位设置成 1。
四次挥手

- 第一次挥手。客户端发起挥手请求,向服务端发送标志位是
FIN报文段,设置序列号seq - 第二次挥手。服务端收到了客户端发送的
FIN报文段,向客户端返回一个标志位是ACK的报文段,ack设为seq加 1 - 第三次挥手。服务端向客户端发送标志位是
FIN的报文段,请求关闭连接,设置序列号seq - 第四次挥手。客户端收到服务端发送的
FIN报文段,向服务端发送标志位是ACK的报文段,ack设为seq加 1。服务端收到客户端的ACK报文段以后,就关闭连接。此时,客户端等待2MSL的时间后依然没有收到回复,则证明服务端已正常关闭,那么客户端也可以关闭连接了。
为什么连接的时候是三次握手,关闭的时候却是四次握手?
建立连接时因为当 Server 端收到 Client 端的 SYN 连接请求报文后,可以直接发送 SYN+ACK 报文。其中 ACK 报文是用来应答的,SYN 报文是用来同步的。所以建立连接只需要三次握手。
由于 TCP 协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,TCP 是全双工模式。
这就意味着,关闭连接时,当 Client 端发出 FIN 报文段时,只是表示 Client 端告诉 Server 端数据已经发送完毕了。当 Server 端收到 FIN 报文并返回 ACK 报文段,表示它已经知道 Client 端没有数据发送了,但是 Server 端还是可以发送数据到 Client 端的,所以 Server 很可能并不会立即关闭 SOCKET,直到 Server 端把数据也发送完毕。
当 Server 端也发送了 FIN 报文段时,这个时候就表示 Server 端也没有数据要发送了,就会告诉 Client 端,我也没有数据要发送了,之后彼此就会愉快的中断这次 TCP 连接。