相关源码:boy-learning-netty
个人博客:http://bruce.bugmakers.club
内容来自《极客时间 - Netty源码剖析与实战》
Netty 是如何处理 TCP 粘包、半包等问题的
-
什么是粘包和半包
-
为什么 TCP 应用中会出现粘包和半包现象
-
解决粘包和半包问题的集中常用方法
-
Netty 对三种常用封帧方式的支持
-
解读 Netty 处理粘包、半包的源码
什么是粘包和半包
粘包
客户端多次发送 ABC, 服务端接收到 ABC? 如:ABCA, ABCAB, ABCABC
主要原因:
- 发送方每次写入数据 < 套接字缓冲区大小
- 接收方读取套接字缓冲区数据不及时
半包
客户端多次发送 ABC, 服务端接收到 A? B? 如:AB, BC, CA
主要原因:
- 发送方每次写入数据 > 套接字缓冲区大小
- 发送的数据大于协议的 MTU(Maximum Transmission Unit, 最大传输单元),必须拆包
换个角度看粘包和半包
- 收发
- 一个发送可能被多次接收,多个发送可能被一次接收
- 传输
- 一个发送可能占用多个传输包,多个发送可能公用一个传输包
为什么 TCP 应用中会出现粘包和半包现象
根本原因:
TCP 是流式协议,消息无边界。
提醒:UDP 像邮寄的包裹,虽然一次运输多个,但每个包裹都有“界限”,一个一个签收,所以无粘包、半包问题。
解决粘包和半包问题的集中常用方法
根本手段:找出消息的边界。
方式\比较 | 寻找消息边界的方式 | 优点 | 缺点 | 推荐度 |
---|---|---|---|---|
TCP 连接改成短连接,一个请求一个短连接 | 建立连接到释放连接之间的信息即为传输信息 | 简单 | 效率低下 | 不推荐 |
封装成帧 Framing - 固定长度 | 满足固定长度即可 | 简单 | 浪费空间 | 不推荐 |
封装成帧 Framing - 分隔符 | 分隔符之间 | 空间不浪费,也比较简单 | 内容本身出现分隔符时需要转义,所以需要扫描内容,耗费资源 | 一般 |
封装成帧 Framing - 固定长度字段储存内容长度信息 | 先解析固定长度字段,再读取后续内容 | 精确定位用户数据,也不用转义 | 长度理论上有限制,需提前预知可能的最大长度从而定义长度占用字节数 | 推荐 |
封装成帧 Framing - 其他方式 | 每种都不同,如JSON可以看{}是否应已经成对 | 衡量实际场景 | 衡量实际场景 | 很多是对现有协议的支持 |
Netty 对三种常用封帧方式的支持
方式\支持 | 解码 | 编码 |
---|---|---|
封装成帧 Framing - 固定长度 | FixedLengthFrameDecoder | 简单 |
封装成帧 Framing - 分隔符 | DelimiterBasedFrameDecoder | 简单 |
封装成帧 Framing - 固定长度字段储存内容长度信息 | LengthFieldBasedFrameDecoder | LengthFieldPrepender |
解读 Netty 处理粘包、半包的源码
-
解码核心工作流程
ByteToMessageDecoder 入手 -
解码中两种数据累计器(Cumulator)的区别
第一种 MERGE_CUMULATOR(默认):内存复制
第二种 COMPOSITE_CUMULATOR:逻辑视图 -
三种解码器的常用额外控制参数有哪些
长度
分隔符(支持一个或多个)
固定长度字段等
网友评论