TCP(Transmission Control Protocol,传输控制协议)是 TCP/IP 协议簇中传输层 的核心协议,专为实现可靠、有序、面向连接的端到端数据传输设计,广泛应用于对数据完整性要求高的场景(如 HTTP、FTP、SMTP 等应用层协议均基于 TCP)。下面从核心特性、工作原理、关键机制三方面详细拆解:
一、TCP 的核心特性
-
面向连接TCP 通信前必须先建立 "连接"(三次握手),通信结束后必须释放连接(四次挥手),类似打电话:先拨号确认对方接听,再通话,最后挂电话。对比 UDP(无连接):UDP 无需建立连接,直接发数据,类似发短信,无法确认对方是否收到。
-
可靠传输 TCP 通过一系列机制保证数据无丢失、无重复、按序到达:
- 确认应答(ACK):接收方收到数据后,必须向发送方返回 "确认报文",发送方若未收到 ACK 则重传;
- 超时重传:发送方发送数据后启动定时器,超时未收到 ACK 则重新发送;
- 差错检测:通过校验和检测数据是否损坏,损坏则丢弃并要求重传;
- 流量控制:避免发送方发得太快,接收方处理不过来(滑动窗口机制);
- 拥塞控制:避免发送方发得太快,导致网络拥堵(慢启动、拥塞避免等算法)。
-
字节流服务TCP 把应用层传递的大数据拆分成若干 "报文段"(Segment)传输,接收方再按顺序拼接还原成完整字节流,对应用层隐藏拆分 / 拼接细节。(注:TCP 不保留报文边界,比如应用层连续发两次 100 字节,TCP 可能合并成 200 字节发送,也可能拆成更小片段,接收方需自行处理边界识别)
-
全双工通信建立连接后,通信双方可同时发送和接收数据(类似双向车道),无需等待对方发送完毕。
二、TCP 的工作流程(三次握手 + 数据传输 + 四次挥手)
1. 连接建立:三次握手(Three-way Handshake)
目的:同步通信双方的序列号和确认号,协商窗口大小,确保双方收发能力正常。
- 第一次握手(SYN):客户端→服务器,发送 SYN 报文(同步序列编号),声明自己的初始序列号(ISN),请求建立连接;
- 第二次握手(SYN+ACK):服务器→客户端,发送 SYN+ACK 报文,确认客户端的 SYN(ACK = 客户端 ISN+1),同时声明自己的初始序列号;
- 第三次握手(ACK):客户端→服务器,发送 ACK 报文,确认服务器的 SYN(ACK = 服务器 ISN+1),连接正式建立。
**为什么需要三次?**如果只有两次握手,服务器无法确认客户端是否能收到自己的 SYN+ACK(可能客户端的 SYN 延迟到达,服务器建立连接后,客户端却没收到确认,导致资源浪费),三次握手能确保双方都确认 "对方能收能发"。

2. 数据传输:基于滑动窗口的可靠传输
- 发送方维护 "发送窗口":表示当前可发送但未确认的字节范围,窗口内的数据可连续发送(无需等一个确认再发下一个),提高传输效率;
- 接收方维护 "接收窗口":表示当前可接收的字节范围,通过 ACK 报文告知发送方窗口大小,实现流量控制;
- 按序重组:接收方按序列号拼接报文段,若中间某段丢失(比如收到 1-100、201-300,缺 101-200),则对已收到的后续数据暂存,等待丢失段重传后再拼接。
3. 连接释放:四次挥手(Four-way Wavehandshake)
目的:确保双方都已完成数据传输,安全释放连接资源。
- 第一次挥手(FIN):主动关闭方→被动关闭方,发送 FIN 报文(终止连接),表示自己已无数据要发送;
- 第二次挥手(ACK):被动关闭方→主动关闭方,发送 ACK 报文,确认收到 FIN(此时被动关闭方仍可发送剩余数据);
- 第三次挥手(FIN):被动关闭方→主动关闭方,发送 FIN 报文,表示自己也无数据要发送;
- 第四次挥手(ACK):主动关闭方→被动关闭方,发送 ACK 报文,确认收到 FIN,等待 2MSL(最大报文段生存时间)(提问为什么需要等待2MSL?(答案再最后面))后释放连接。
**为什么需要四次?**因为 TCP 是全双工通信,关闭连接时需要分别关闭 "发送方向" 和 "接收方向":第一次 FIN 关闭主动方的发送方向,第二次 ACK 确认;第三次 FIN 关闭被动方的发送方向,第四次 ACK 确认,因此需要四次。

三、TCP 的关键机制(保证可靠性的核心)
1. 流量控制(Flow Control)
- 作用:避免接收方缓冲区溢出(发送方速度 > 接收方处理速度);
- 实现:接收方通过 TCP 报文头部的 "窗口大小" 字段,告知发送方自己当前可用的缓冲区大小,发送方根据该值调整发送速率;
- 核心:滑动窗口(Sliding Window)------ 窗口大小动态变化,接收方缓冲区空闲越多,窗口越大,发送方发送越快;缓冲区满则窗口为 0,发送方停止发送。
2. 拥塞控制(Congestion Control)
- 作用:避免发送方速度 > 网络承载能力(导致网络拥堵、丢包);
- 核心算法:
- 慢启动(Slow Start):连接建立后,发送方从小窗口开始(初始窗口 = 1 个报文段),每收到一个 ACK,窗口大小翻倍,直到达到 "慢启动阈值";
- 拥塞避免(Congestion Avoidance):达到阈值后,窗口大小每次加 1(线性增长),避免指数增长导致拥堵;
- 快速重传(Fast Retransmit):若接收方收到乱序报文,立即发送重复 ACK,发送方收到 3 个重复 ACK 后,无需等待超时就重传丢失报文;
- 快速恢复(Fast Recovery):重传后,窗口大小调整为慢启动阈值的一半,进入拥塞避免阶段,无需重新慢启动。
3. 超时重传与重传计时器
- 发送方为每个发送的报文段启动计时器,超时时间(RTO)根据 "往返时间(RTT)" 动态调整(RTT 是数据发送到收到 ACK 的时间);
- 若超时未收到 ACK,立即重传该报文段,同时调整 RTO(避免因网络延迟导致误判丢包)。
4. 校验和(Checksum)
- TCP 报文头部和数据部分都会计算校验和,接收方收到后重新计算,若与报文携带的校验和不一致,说明数据损坏,直接丢弃并要求重传。
四、TCP 的适用场景
- 对可靠性要求高的场景:网页浏览(HTTP/HTTPS)、文件传输(FTP)、邮件收发(SMTP/POP3)、远程登录(SSH/Telnet);
- 不适用场景:实时性要求高的场景(如视频通话、游戏)------TCP 的重传机制会导致延迟,这类场景通常用 UDP + 应用层可靠机制实现。
五、TCP 报文结构(简要)
TCP 报文由 "头部 + 数据" 组成,头部固定 20 字节(可选字段最多扩展到 60 字节),关键字段:
- 源端口 / 目的端口:标识通信的应用程序(如 HTTP 用 80 端口);
- 序列号(Seq):当前报文段数据的起始字节编号;
- 确认号(Ack):期望收到的下一个报文段的序列号(即已收到 Ack-1 之前的所有数据);
- 窗口大小:接收方当前可用的缓冲区大小(流量控制核心);
- 标志位(Flags):SYN(同步)、ACK(确认)、FIN(终止)、RST(重置连接)、PSH(推送数据)、URG(紧急数据)。
六、问题解答
1、再TCP四次挥手士主动关闭方为什么需要等待2MSL(或者为什么主动关闭方有一个TIME-WAIT的状态)?
TCP 设计 TIME-WAIT 状态并设置 2MSL 时长,本质是为了解决两个关键问题:确保连接可靠关闭 和防止旧连接的过期报文干扰新连接,这两个问题都与 TCP 报文在网络中的 "生命周期" 直接相关。
1. 确保连接能 "可靠关闭":给最后一个 ACK 报文 "容错时间"
TCP 四次挥手的最终关闭流程是:
- 主动关闭方(如客户端)发送
FIN报文(请求关闭)→ 被动关闭方(如服务器)回复FIN+ACK(同意关闭,并请求自己的关闭)→ 主动关闭方回复ACK(确认收到服务器的关闭请求)。
这里的关键风险是:最后一个 ACK 报文可能丢失(比如网络波动)。
- 若 ACK 丢失,被动关闭方(服务器)会因为没收到确认,在超时后重传
FIN报文(因为服务器认为自己的FIN没被收到)。 - 主动关闭方(客户端)在
TIME-WAIT状态下(持续 2MSL),就能收到这个重传的FIN报文,此时会重新发送 ACK 并重置 2MSL 计时器 ------ 确保服务器最终能收到确认,顺利进入CLOSED状态。
如果没有 2MSL 的等待:
- 客户端发送 ACK 后直接关闭,若 ACK 丢失,服务器会一直重传
FIN却收不到回应,最终因超时进入错误关闭状态(连接未正常释放)。
2. 防止 "旧连接的过期报文" 干扰 "新连接":给旧报文 "消亡时间"
TCP 连接的唯一标识是 "源 IP + 源端口 + 目的 IP + 目的端口"(四元组)。实际场景中,同一台机器可能在短时间内用相同四元组建立新连接(比如客户端断开后立即重连服务器,端口复用)。
此时的风险是:上一个连接中残留的 "过期报文"(因网络延迟未及时到达)可能闯入新连接。
- 旧报文的序号属于上一个连接的序号范围,若新连接恰好使用相同四元组,TCP 会误认为这是新连接的正常报文,导致数据错乱。
2MSL 的等待正是为了避免这种情况:
- MSL 是 "报文在网络中能存活的最长时间"(比如 1 分钟),意味着旧连接的任何报文最多在网络中跑 1 分钟就会被丢弃。
- 2MSL 则覆盖了 "旧报文从主动方到被动方,再从被动方返回主动方" 的最长往返时间 ------ 确保在
TIME-WAIT结束时,网络中所有属于上一个连接的报文都已彻底消失。
如果没有 2MSL 的等待:
- 新连接建立后,可能收到上一个连接的旧报文,TCP 会根据序号处理(若序号在新连接的接收窗口内),导致数据错误或连接异常。
总结:2MSL 是 "双重保险"
- 对 "连接关闭":用 2MSL 确保最后一个 ACK 能被对方收到(或重传后收到),避免被动方卡在关闭流程中。
- 对 "新连接安全":用 2MSL 确保旧连接的所有报文已从网络中消亡,避免干扰复用相同四元组的新连接。
这也是为什么 TIME-WAIT 状态只能由 "主动关闭方" 承担(被动关闭方在收到最后一个 ACK 后直接进入 CLOSED)------ 因为主动关闭方是最后一个发送报文的角色,需要对 "报文是否送达" 和 "旧报文是否清除" 负责。