目录
- 一、固定分隔符方式解决粘包问题(代码示例)
- 1.1、固定分隔符解决粘包问题的服务端代码示例
- 1.2、固定分隔符方式解决粘包问题的客户端代码示例
- 1.3、分别启动服务端,客户端,查看服务端结果输出
一、固定分隔符方式解决粘包问题(代码示例)
1.1、固定分隔符解决粘包问题的服务端代码示例
-
默认以 \n作为分隔符,如果超出指定长度(假设长度为 1024个 字节)仍未出现分隔符,则抛出异常。服务端加入如下代码:
ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
-
服务端完整代码示例
package com.example.nettytest.netty.day5; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.LineBasedFrameDecoder; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import lombok.extern.slf4j.Slf4j; /** * @description: 固定分隔符方式解决粘包 问题服务端示例 * @author: xz */ @Slf4j public class NettySeparatorServer { public static void main(String[] args) { new NettySeparatorServer().start(); } void start() { NioEventLoopGroup boss = new NioEventLoopGroup(); NioEventLoopGroup worker = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap() .channel(NioServerSocketChannel.class) //调整 netty 的接受缓冲区(byteBuf) .childOption(ChannelOption.RCVBUF_ALLOCATOR,new AdaptiveRecvByteBufAllocator(16,16,16)) .group(boss, worker) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { //设置行解码器,默认以 \n (换行符)作为分隔符,如果超出指定长度(假设指定长度1024)仍未出现分隔符,则抛出异常 ch.pipeline().addLast(new LineBasedFrameDecoder(1024)); ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG)); ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { //会在连接channel建立成功后,触发active事件 @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { log.debug("connected>>>>>>>>>>>>>>>> {}", ctx.channel()); super.channelActive(ctx); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { log.debug("disconnect>>>>>>>>>>>>>>>> {}", ctx.channel()); super.channelInactive(ctx); } }); } }); ChannelFuture channelFuture = serverBootstrap.bind(8080); log.debug("{}>>>>>>>>>>>>>>>> binding...", channelFuture.channel()); channelFuture.sync(); log.debug("{}>>>>>>>>>>>>>>>> bound...", channelFuture.channel()); channelFuture.channel().closeFuture().sync(); } catch (InterruptedException e) { log.error("server error", e); } finally { boss.shutdownGracefully(); worker.shutdownGracefully(); log.debug(">>>>>>>>>>>>>>>>stoped"); } } }
1.2、固定分隔符方式解决粘包问题的客户端代码示例
-
客户端代码示例
package com.example.nettytest.netty.day5; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import lombok.extern.slf4j.Slf4j; import java.util.Random; /** * @description: 固定分隔符方式解决粘包 问题客户端示例 * @author: xz */ @Slf4j public class NettySeparatorClient { public static void main(String[] args) { send(); } public static StringBuilder makeString(char c, int len) { StringBuilder sb = new StringBuilder(len + 2); for (int i = 0; i < len; i++) { sb.append(c); } sb.append("\n"); return sb; } private static void send() { NioEventLoopGroup worker = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.channel(NioSocketChannel.class); bootstrap.group(worker); bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { log.debug("connetted..."); ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG)); ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { // 会在连接 channel 建立成功后,会触发 active 事件 @Override public void channelActive(ChannelHandlerContext ctx) { log.debug("sending..."); ByteBuf buf = ctx.alloc().buffer(); char c = '0'; Random r = new Random(); for (int i = 0; i < 10; i++) { StringBuilder sb = makeString(c, r.nextInt(256) + 1); c++; buf.writeBytes(sb.toString().getBytes()); } ctx.writeAndFlush(buf); } }); } }); ChannelFuture channelFuture = bootstrap.connect("localhost", 8080).sync(); channelFuture.channel().closeFuture().sync(); } catch (InterruptedException e) { log.error("client error", e); } finally { worker.shutdownGracefully(); } } }
1.3、分别启动服务端,客户端,查看服务端结果输出
- 先启动服务端
- 再启动客户端,输入日志如下:
```
-
再次查看服务端,日志如下:
由输出结果可知,固定分隔符方式解决粘包问题的缺点:处理字符数据比较合适,但如果内容本身包含了分隔符(字节数据常常会有此情况),那么就会解析错误。