1、什么是粘包/拆包
一般所谓的TCP粘包是在一次接收数据不能完全地体现一个完整的消息数据。TCP通讯为何存在粘包呢?主要原因是TCP是以流的方式来处理数据,再加上网络上MTU的往往小于在应用处理的消息数据,所以就会引发一次接收的数据无法满足消息的需要,导致粘包的存在。处理粘包的唯一方法就是制定应用层的数据通讯协议,通过协议来规范现有接收的数据是否满足消息数据的需要。
2、解决办法
2.1、消息定长,报文大小固定长度,不够空格补全,发送和接收方遵循相同的约定,这样即使粘包了通过接收方编程实现获取定长报文也能区分。
2.2、包尾添加特殊分隔符,例如每条报文结束都添加回车换行符(例如FTP协议)或者指定特殊字符作为报文分隔符,接收方通过特殊分隔符切分报文区分。
2.3、将消息分为消息头和消息体,消息头中包含表示信息的总长度(或者消息体长度)的字段
3、netty server端设置特殊分隔符
- 注意:分隔符一定要在数据处理的handler之前指定
@Component
public class NettyServer {
@Value("${netty.server.port}")
private int port;
/**
* 启动 netty server
* @throws InterruptedException
*/
public void start() {
EventLoopGroup parentGroup = new NioEventLoopGroup();
EventLoopGroup childGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(parentGroup, childGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, Integer.parseInt(CommonUtils.getConfig("ChannelOption.SO_BACKLOG"))) // 设置线程队列得到连接个数
.option(ChannelOption.SO_KEEPALIVE, true) // 设置保持连接的活动状态
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
// 注意消息分隔符处理的handler一定要在消息处理逻辑前面
ByteBuf buf = Unpooled.copiedBuffer("\t", Charset.defaultCharset());//自定义拆包字符
//(1024)解码的帧的最大长度,false(拆包是否去掉指定字符),buf(拆包字符)
DelimiterBasedFrameDecoder delimiterBasedFrameDecoder = new DelimiterBasedFrameDecoder(1400, true, buf);
ch.pipeline().addLast(delimiterBasedFrameDecoder);
ch.pipeline().addLast(new NettyServerHandler2());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
parentGroup.shutdownGracefully().sync();
childGroup.shutdownGracefully().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
来源:oschina
链接:https://my.oschina.net/u/4252423/blog/4890565