TCP 协议的特点、三次握手建连、四次挥手断连
TCP 协议的特点
-
位于 OSI 模型的第四层:传输层
-
面向连接
TCP 是基于连接的,也就是传输数据前需要先建立好连接,然后再进行传输。 -
双工通信
TCP 连接一旦建立,就可以在连接上进行双向的通信。 -
可靠
TCP 的传输是基于字节流,而不是报文。将数据按字节大小进行编号,接收端通过 ACK 来确认收到的数据编号。通过这种机制,TCP 协议能够保证接收数据的有序性和完整性。因此 TCP 能够提供可靠性传输。 -
流量控制
TCP 还提供流量控制能力,通过滑动窗口来控制数据的发送速率。滑动窗口的本质是动态缓冲区,接收端根据自己的处理能力,在 TCP 的 Header 中动态调整窗口的大小,通过 ACK 应答包通知给发送端,发送端根据窗口的大小调整发送速率。 -
拥塞控制
仅仅有了流量控制能力还不够,TCP 协议还考虑到了网络问题可能会导致大量重传,进而导致网络情况进一步恶化。因此 TCP 协议还提供了拥塞控制。TCP 处理拥塞控制主要是用到了慢启动、拥塞避免、拥塞发生、快速恢复四个算法。
除了 TCP 协议的特点,还可以进一步了解 TCP 协议的报文状态、滑动窗口的工作流程、keepAlive 的参数设置和 Nagel 算法的规则等一些细节。
另外还有典型的 TCP 协议问题,例如:特定场景下 Nagel 和 Ask 延迟机制配合使用,可能会出现延迟 40 毫秒超时后才能回复 ACK 包的问题。
TCP 三次握手建连
-
TCP 是基于连接的,所以在传输数据前需要先建立连接。
-
TCP 在传输上是双工传输,不区分 Client 端与 Server 端。为了便于理解,我们把主动发起建连请求的一端称作 Client 端,把被动建立连接的一端称作 Server 端。
-
首先建立连接前需要 Server 端先监听端口,因此 Server 端建立连接前的初始状态就是 LISTEN 状态。
-
这时 Client 端,准备建立连接,先发送一个 SYN 同步包。发送完同步包后,Client 端的连接状态就变成了 SYN_SENT 的状态。
-
Server 端收到 SYN 后同意建立连接,会向 Client 端回复一个 ACK。由于 TCP 是双工传输,Server 端同时也会向 Client 端发送一个同步请求 SYN,申请 Server 向 Client 方向建立连接,发送完 ACK 和 SYN 后,Server 端的连接状态就变成了 SYN_RCVD 状态。
-
Client 端收到 Server 端的 ACK 后,Client 端的连接状态就变成了 ESTABLISHED 状态。同时 Client 端向 Server 端发送 ACK 响应,回复 Server 端的 SYN 请求。
-
Server 端收到 Client 端的 ACK 后,Server 端的连接状态,也就变成了 ESTABLISHED 状态。
-
此时建连完成,双方随时可以进行数据传输。
在面试时需要明白三次握手是为了建立双向的连接,需要记住 Client 端和 Server 端的连接状态变化。
另外回答建连的问题时,可以提到 SYN 洪水攻击发生的原因,就是 Server 端收到 Client 端的 SYN 请求后发送了 ACK 和 SYN,但是 Client 端不进行回复,导致 Server 端大量的连接处在 SYN_RCVD 状态,进而影响其他正常请求的界面。
解决办法:
可以通过设置 Linux 的 TCP 参数 tcp_synack_retries=0,加快对于半连接的回收速度,或者调大 tcp_max_syn_backlog 来应对少量的 SYN 洪水攻击。
TCP 四次挥手断连
-
TCP 连接的关闭,通讯双方都可以先发起。我们暂且把先发起的一方看作 Client 端。
-
从图中可以看出,通信中的 Client 端和 Server 端的连接状态都是 ESTABLISHED 状态,然后 Client 端先发起了关闭连接的请求。Client 端向 Server端发送了一个 FIN 包,表示 Client 端已经没有数据要发送的了,然后 Client 端就进入了 FIN_WAIT_1 状态。
-
Server 端收到 FIN 后回复 ACK,然后进入 CLOST_WAIT 状态。此时 Server 端属于半关闭状态,因为此时 Client 端向 Server 端方向已经不会再发送数据了,可是 Server 端向 Client 端可能还有数据要发送。
-
Client 端在接收到 Server 端回复的 ACK 后变成 FIN_WAIT_2 状态。
-
当 Server 端数据发送完毕后,Server 端会向 Client 端发送 FIN 表示 Server 端也没有数据要发送。这时 Server 端进入 LAST_ACK 状态,等待 Client 端的应答就可以关闭连接了。
-
Client 端收到 Server 端的 FIN 后回复 ACK,然后进入 TIME_WAIT 状态。TIME_WAIT 状态下需要等待两倍的 MSL(也就是最大报文段生存时间),来保证连接的可靠关闭。之后才会进入 CLOSED 状态。而 Server 端收到 ACK 后直接就可以进入 CLOSED 状态。
为什么需要等待两倍的 MSL 之后才能关闭连接?
原因有两个:
第一,要保证 TCP 协议的全双工连接能够可靠关闭;
第二,要保证这次连接中重复的数据段能够从网络中消失,防止端口被重用的时候可能会产生数据混淆。
为什么建连是三次握手,断连却要四次挥手?
从这个交互流程上可以看出,无论是建连还是断连,都是需要在两个方向上进行。
只不过建连时 Server 端的 SYN 和 ACK 两个包合并为一次发送,而断开连接时两个方向的数据发送的停止时间可能是不同的,所以无法合并 FIN 和 ACK 发送,这就是建连的时候必须要三次握手,而断连的时候必须要四次挥手的原因。
From:偶像-新浪微博资深技术专家 张雷