JavaEE 初阶第二十四期:网络原理,底层框架的“通关密码”(四)
专栏:JavaEE初阶起飞计划
个人主页:手握风云
目录
一、TCP协议
1.1. 延迟应答
1.2. 捎带应答
1.3. 面向字节流和粘包问题
1.4. 异常情况
1. 连接中断类异常
2. 传输异常类
3. 状态异常类
二、TCP和UDP对比
2.1. 基础特性
2.2. 核心机制
1. 连接管理
2. 可靠性保障
3. 效率和开销
4.应用层影响
一、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 直接获取完整包。