Netty 解决粘包/半包问题
解决Tcp粘包问题的主流方法有如下几种
客户端和服务端应用程序在接收数据时按 换行符进行分包 --Netty中的LineBasedFrameDecoder
客户端和服务端应用程序在接收数据时按指定分隔符 进行分包–Netty中的DelimiterBasedFramDecoder
客户端和服务端应用程序在接收数据时按固定长度进行分包–Netty中的FixedLengthFrameDecoder
客户端和服务端应用程序在收发数据时按块编码, (需要自己实现,Netty未提供编码/解码器)
格式:100 (标志位,第一个字节表示数据的长度)xxx (数据体,100个字节的数据体)
…
0 (标志位,数据结束,数据包中完整的数据已读取完成)
一、按换行符分包
private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel arg0) throws Exception {
// 配置按换行符解码器;设置一行的最大长度。
arg0.pipeline().addLast(new LineBasedFrameDecoder(1024));
arg0.pipeline().addLast(new TimeServerHandler());
}
二、按特定字符分包
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ByteBuf delimiter = Unpooled.copiedBuffer("$_"
.getBytes());
// 以$_作为分包
ch.pipeline().addLast(
new DelimiterBasedFrameDecoder(1024,
delimiter));
ch.pipeline().addLast(new EchoServerHandler());
}
三、固定长度分包
@Override
public void initChannel(SocketChannel ch)
throws Exception {
// 每20个字节分一个包
ch.pipeline().addLast(
new FixedLengthFrameDecoder(20));
ch.pipeline().addLast(new EchoServerHandler());
}
小结
具体选用哪种方式由应用的业务场景决定
- 如果传输的数据类型是文本,并且文本很小,可以按照换行符/指定分隔符来分包;
- 如果传输的是二进制类型(文件上传、下载),可以使用按块编码进行分包;
- 按固定长度分包,发送端需要对不满长度的包进行填充字符。(不推荐使用)