


专栏:JavaEE初阶起飞计划
个人主页:手握风云
目录
[1.1. 延迟应答](#1.1. 延迟应答)
[1.2. 捎带应答](#1.2. 捎带应答)
[1.3. 面向字节流和粘包问题](#1.3. 面向字节流和粘包问题)
[1.4. 异常情况](#1.4. 异常情况)
[1. 连接中断类异常](#1. 连接中断类异常)
[2. 传输异常类](#2. 传输异常类)
[3. 状态异常类](#3. 状态异常类)
[2.1. 基础特性](#2.1. 基础特性)
[2.2. 核心机制](#2.2. 核心机制)
[1. 连接管理](#1. 连接管理)
[2. 可靠性保障](#2. 可靠性保障)
[3. 效率和开销](#3. 效率和开销)
一、TCP协议
1.1. 延迟应答
延迟应答承接滑动窗口,是TCP 协议中一种通过"延迟发送确认应答(ACK)"来优化网络传输效率的机制。核心目标:扩大窗口大小,避免接收端立即应答导致窗口过小,通过等待应用层消费数据,使返回的窗口值更大,提升吞吐量。减少冗余ACK,合并多个数据段的确认,降低网络中 ACK 报文的数量,减轻带宽压力。
触发条件:默认等待 200ms,若期间无新数据到达,则发送 ACK。延时应答,生效的前提得是期间没有新的ACK过来。但从实践经验来看,延时应答还是有效果的。
- 数量限制:每隔N个包就应答一次;
- 时间限制:超过最大延迟时间就应答一次。
1.2. 捎带应答
很多情况下,客户端服务器在应用层是"一问一答"的模型,也就是客户端发送request,服务器回一个response。

返回ACK的时机,是在收到请求之后立即返回的。而返回响应的时机,需要服务器进行一定的计算,这个过程比较复杂,时间比较长。但是TCP会有延时应答,一推迟正好赶上TCP返回响应,就可以直接把ACK报文和响应数据,做成一个TCP数据报返回给客户端就可以了。普通的响应报文ACK这一位是0,确认序号都是无效的,窗口大小也无效。ACK只有报头,没有载荷,报头中关键的就是ACK、确认序号、窗口大小。
捎带应答是延迟应答的 "强化版":接收端在延迟等待期间,若有上行数据(如服务器响应),则将ACK搭载在数据帧中发送,避免单独ACK。捎带应答,既取决于延时应答,又和应用程序的处理逻辑有关,不是100%触发的。
1.3. 面向字节流和粘包问题
创建⼀个TCP的socket,同时在内核中创建一个发送缓冲区和接收缓冲区。TCP是面向字节流的协议,意味着TCP将应用层数据视为连续的字节序列,不保留消息边界。发送方多次wirte的数据可能被合并为一个TCP段,接收方多次read也可能拆分同一个TCP段。
- 字节流的拆分与合并
发送方:若write100byte分10次写,TCP 可能合并为一个段发送;若write100byte(超过 MTU),则拆分为多个段。接收方:read10byte可能读取一个段的部分字节,剩余部分留在缓冲区,下read继续读取。比如发送 "ABC" + "DEF",接收端可能读到 "AB" + "CDEF",或 "ABCDEF",取决于缓冲区状态。
- 粘包问题(本质:边界模糊)
应用层无法区分多个逻辑消息的边界,这就是粘包现象,因为TCP 仅保证字节流顺序,不维护消息边界。要想解决粘包问题,得从应用层入手,合理地设计应用层协议,让包之间的边界比较清晰。比如定长消息,如每个消息固定 1024 字节,不足补填充;使用分隔符,使用特殊字符(如\r\n)标识消息结束。
1.4. 异常情况
1. 连接中断类异常
-
进程终止 / 机器重启
- 现象:程序释放文件描述符,触发FIN挥手(与正常关闭一致)。
- 处理:接收端收到FIN后进入CLOSE_WAIT,若未及时close(),会导致大量CLOSE_WAIT堆积(需检查代码是否漏关连接)。
-
机器掉电 / 网线断开
- 现象:接收端认为连接存活,若尝试写数据,触发RST重置(内核保活定时器定期探测,超时后释放连接)。
- 处理:依赖 TCP 内置的保活定时器,或应用层心跳机制。
2. 传输异常类
-
数据包丢失
- 机制:超时重传(指数退避)+ 快速重传(3 次重复ACK)。
- 优化:动态计算超时时间(基于 RTT 估计),避免频繁重传或延迟过高。
-
乱序 / 重复包
- 处理:序列号确保按序重组,重复包通过ACK去重。
3. 状态异常类
-
TIME_WAIT 过多
- 原因:主动关闭方等待 2MSL,防止旧连接数据包干扰新连接。
- 影响:端口占用,高并发时可能导致端口耗尽。
-
CLOSE_WAIT 泄漏
- 原因:被动关闭方未调用close(),导致四次挥手未完成。
- 解决:检查服务器代码,确保响应完成后关闭连接。
二、TCP和UDP对比
2.1. 基础特性
|------|--------------------|---------|
| 特性 | TCP协议 | UDP协议 |
| 连接性 | 三次握手建立,四次挥手断开 | 无连接 |
| 可靠性 | 可靠 | 不可靠 |
| 有序性 | 严格按序 | 可能乱序 |
| 流量控制 | 滑动窗口 | 无 |
| 拥塞控制 | 支持 | 无 |
| 头部开销 | 20-60 字节 | 固定 8 字节 |
| 传输单位 | 字节流(无消息边界,依赖应用层拆包) | 数据报 |
2.2. 核心机制
1. 连接管理
- TCP :
- 三次握手:
SYN → SYN+ACK → ACK
,确保双方收发能力正常。 - 四次挥手:
FIN → ACK → FIN → ACK
,允许半关闭(CLOSE_WAIT 状态),避免数据丢失。
- 三次握手:
- UDP:无连接,类似 "发邮件",无需确认对方是否在线。
2. 可靠性保障
- TCP :
- 序列号:每个字节编号,接收端按序重组。
- 超时重传:未收到 ACK 时,指数退避重传(如超时 500ms→1000ms→2000ms)。
- 快速重传:3 次重复 ACK 触发重传,无需等待超时(文档滑动窗口部分)。
- UDP:无重传,丢包后应用层需自行处理(如视频流丢帧直接丢弃,依赖实时性)。
3. 效率和开销
- TCP :
- 延迟较高(握手、ACK、拥塞控制),但吞吐量稳定(适合大文件传输)。
- MSS 协商:通过 MTU 计算最大分段大小,避免 IP 分片。
- UDP :
- 低延迟(无连接、无确认),适合实时场景(如游戏、直播)。
- 易分片:数据超过 MTU 时强制分片,任一丢失则整体丢弃。
4.应用层影响
- TCP 粘包问题:字节流无边界,需应用层自定义拆包(如定长、分隔符、长度前缀)。
- UDP 消息边界:数据报独立,recvfrom 直接获取完整包。