Netty解决TCP拆包粘包的问题(一)
作者:互联网
一个小的Socket Buffer问题
在基于流的传输里比如TCP/IP,接收到的数据会先被存储到一个socket接收缓冲里。不幸的是,基于流的传输并不是一个数据包队列,而是一个字节队列。即使你发送了2个独立的数据包,操作系统也不会作为2个消息处理而仅仅是作为一连串的字节而言。因此这是不能保证你远程写入的数据就会准确地读取。举个例子,让我们假设操作系统的TCP/TP协议栈已经接收了3个数据包:
由于基于流传输的协议的这种普通的性质,在你的应用程序里读取数据的时候会有很高的可能性被分成下面的片段。
因此,一个接收方不管他是客户端还是服务端,都应该把接收到的数据整理成一个或者多个更有意思并且能够让程序的业务逻辑更好理解的数据。在上面的例子中,接收到的数据应该被构造成下面的格式:
业内主流的三种解决方案
1.消息定长,例如每个报文固定大小为200个字节,如果不够则用空格补全
2.在包尾部增加特殊字符进行分割
3.将消息分为消息头和消息体,在消息头中包含表示消息总长度的字段,然后进行业务逻辑的处理(自定义协议)
Netty中有两个类用以解决拆包和粘包的问题
1.DelimiterBaseFrameDecoder(自定义分隔符类)
2.FixLengthFrameDecoder(定长类)
//1 第一个线程组 是用于接收Client端连接的
EventLoopGroup bossGroup = new NioEventLoopGroup();
//2 第二个线程组 是用于实际的业务处理操作的
EventLoopGroup workerGroup = new NioEventLoopGroup();
//3 创建一个辅助类Bootstrap,就是对我们的Server进行一系列的配置
ServerBootstrap b = new ServerBootstrap();
//把俩个工作线程组加入进来
b.group(bossGroup, workerGroup)
//我要指定使用NioServerSocketChannel这种类型的通道
.channel(NioServerSocketChannel.class)
//一定要使用 childHandler 去绑定具体的 事件处理器
//在这里解决拆包粘包的问题
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
//设置特殊分隔符
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf));
//设置字符串的解码格式
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ServerHandler());
}
})
clinet端
ChannelFuture cf1 = b.connect("127.0.0.1", 8765).sync();
//buf writeAndFlush写入缓冲区并推给服务端
cf1.channel().writeAndFlush(Unpooled.copiedBuffer("777$_".getBytes()));
cf1.channel().writeAndFlush(Unpooled.copiedBuffer("0000$_".getBytes()));
cf1.channel().writeAndFlush(Unpooled.copiedBuffer("722456$_".getBytes()));
耳听代码
发布了8 篇原创文章 · 获赞 0 · 访问量 157
私信
关注
标签:Netty,copiedBuffer,TCP,粘包,new,接收,getBytes,channel,cf1 来源: https://blog.csdn.net/weixin_36802143/article/details/104521428