粘包与半包
假设客户端分别发送了两个数据包D1和D2给服务端,由于服务端一次读取到的字节数是不确定的,故可能存在以下4种情况。
- 服务端分两次读取到了两个独立的数据包,分别是D1和D2,没有粘包和拆包;
- 服务端一次接收到了两个数据包,D1和D2粘合在一起,被称为TCP粘包;
- 服务端分两次读取到了两个数据包,第一次读取到了完整的D1包和D2包的部分内容,第二次读取到了D2包的剩余内容,这被称为TCP拆包;
- 服务端分两次读取到了两个数据包,第一次读取到了D1包的部分内容D1_1,第二次读取到了D1包的剩余内容D1_2和D2包的整包;
- 如果此时服务端TCP接收滑窗非常小,而数据包D1和D2比较大,很有可能会发生第五种可能,即服务端分多次才能将D1和D2包接收完全,期间发生多次拆包。
粘包发生原因:
- 发送方每次写入数据 < 套接字缓冲区大小;
- 接收方读取套接字缓冲区的数据不够及时。
半包发生原因:
- 发送方写入数据 > 套接字缓冲区大小
- 发送的数据大于协议的MTU(最大传输单元),必须拆包
根本原因:
TCP是流式协议,消息无边界
Netty对封帧方式的支持
| 方式\支持 | 解码 | 编码 | |
封帧 (Framing) |
固定长度 | FixedLengthFrameDecoder | 简单 |
| 分隔符 | DelimiterBasedFrameDecoder | ||
| 固定长度字段存个内容的长度信息 | LengthFieldBasedFrameDecoder | LengthFieldPrepender | |