Netty框架之TCP粘包/半包解决方案
谈到TCP粘包/半包的解决方案,我们不妨先认识造成TCP粘包/半包的原因有哪些,以便于更深刻理解解决方案的原理
一.TCP粘包
1.现象:发送:abc,def,接收:abcdef
2.原因:
- 应用层:接受数据的Bytebuf缓冲区设置太大(Netty默认为1024)存储了多个TCP包,一次性取的时候取出缓冲区所有数据,导致多个包粘在一起.
- 滑动窗口:发送方发送消息太快,接收方接收消息也快,但是处理消息太慢,并且接收窗口足够大,那么此时消息就会堆积在接收窗口,那么就会导致多个包粘在一起
- Nagle算法:Nagle算法是操作系统底层自动实现的,为了减少发送次数,提高效率,操作系统会在缓冲区未满的时候等待消息填充,直到缓冲区满的时候一并发送,造成粘包
二.TCP半包
1.现象:发送:abcdef,接收:abc,def
2.原因:
- 应用层:接受数据的Bytebuf缓冲区设置太小(Netty默认为1024)存储不了一个完整的TCP包,一次性只能取出TCP包的部分数据
- 滑动窗口:发送方发送窗口较大,接收方接收窗口较小,导致接收方只能接收TCP包的部分数据,导致TCP半包
- MSS限制:为了限制TCP包的大小,会将大的TCP包分组成多个小的TCP包发送,导致半包问题
三.TCP粘包/半包解决方案
1.FixedLengthFrameDecoder定长解析器
向pipeline中加入FixedLengthFrameDecoder(int length)定长解析器,取出指定字节长度的数据作为完成数据,不过这要求完整数据的长度是定长
使用方法,请尝试理解下面源码
public class FixedLengthFrameDecoderTest {
public static ByteBuf Message(){
StringBuilder sb = new StringBuilder();
char c = 'a';
for(int i=0;i<20;i++){
sb.append(c);
c++;
}
return Unpooled.copiedBuffer(sb.toString(),StandardCharsets.UTF_8);
}
public static void main(String[] args) {
EmbeddedChannel channel = new EmbeddedChannel(
//定长解析器,取出指定字节长度的数据
new FixedLengthFrameDecoder(10),
new SimpleChannelInboundHandler<ByteBuf>() {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf