netty(一) 利用 LineBasedFrameDecoder,StringDecoder解决TCP粘包/拆包问题

举报
小米粒-biubiubiu 发表于 2020/12/01 00:37:17 2020/12/01
2.9k+ 0 0
【摘要】 .一,TCP粘包/拆包问题图示 产生TCP粘包/拆包问题如下几点: TCP粘包/拆包问题解决方案:   二,利用 LineBasedFrameDecoder,StringDecoder解决TCP粘包/拆包问题  server端代码示例: package nettyDemo3; import io.netty.bootstrap.ServerBoot...

.一,TCP粘包/拆包问题图示

产生TCP粘包/拆包问题如下几点:

TCP粘包/拆包问题解决方案:

二,利用 LineBasedFrameDecoder,StringDecoder解决TCP粘包/拆包问题 

server端代码示例:


      package nettyDemo3;
      import io.netty.bootstrap.ServerBootstrap;
      import io.netty.buffer.ByteBuf;
      import io.netty.buffer.Unpooled;
      import io.netty.channel.ChannelFuture;
      import io.netty.channel.ChannelHandlerAdapter;
      import io.netty.channel.ChannelHandlerContext;
      import io.netty.channel.ChannelInitializer;
      import io.netty.channel.ChannelOption;
      import io.netty.channel.EventLoopGroup;
      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.codec.string.StringDecoder;
      public class TimeServerHanler extends ChannelHandlerAdapter {
     	private int counter; // 计数器
     	/**
       * 抛异常会调用此方法
       */
     	@Override
     	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
     		// TODO Auto-generated method stub
     		// super.exceptionCaught(ctx, cause);
      		cause.printStackTrace();
      		ctx.close();
      	}
     	/**
       * 读取客户端回应的消息
       */
     	@Override
     	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
     		// TODO Auto-generated method stub
     		// super.channelRead(ctx, msg);
     		// ByteBuf buf = (ByteBuf) msg;
     		// byte[] bytes = new byte[buf.readableBytes()];
     		// buf.readBytes(bytes);
     		// String body = new String(bytes, "UTF-8");
     		// System.getProperty("line.separator") 换行符
      		String body = (String) msg;
      		System.out.println(body + "【第" + (++counter) + "次收到客户端的消息】");
      		String result = "i am server" + System.getProperty("line.separator");
      		ByteBuf buf2 = Unpooled.copiedBuffer(result.getBytes());
      		ctx.write(buf2);
      	}
     	/**
       * 读取完成之后会调用此方法
       */
     	@Override
     	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
     		// TODO Auto-generated method stub
     		// super.channelReadComplete(ctx);
      		ctx.flush();
      		System.out.println("读取完成");
      	}
     	public static void main(String[] args) {
     		// 配置服务端线程组,一个负责连接 ,一个负责读写
      		EventLoopGroup boss = new NioEventLoopGroup();
      		EventLoopGroup worker = new NioEventLoopGroup();
     		try {
     			// 创建服务端辅助启动类并设置参数
      			ServerBootstrap bootstrap = new ServerBootstrap();
      			bootstrap.group(boss, worker).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)
       .handler(new LoggingHandler(LogLevel.INFO))
       .childHandler(new ChannelInitializer<SocketChannel>() {
      @Override
      protected void initChannel(SocketChannel ch) throws Exception {
      // TODO Auto-generated method stub
      // 添加回车换行符解码器
       ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
       ch.pipeline().addLast(new StringDecoder());
       ch.pipeline().addLast(new TimeServerHanler());
       }
       });
     			int inetPort = 8080;
     			// 绑定端口,并开始阻塞等待客户端的连接
      			ChannelFuture f = bootstrap.bind(inetPort).sync();
      			f.channel().closeFuture().sync();
      		} catch (Exception e) {
      			e.printStackTrace();
      		} finally {
     			// 优雅退出,释放线程池资源
      			boss.shutdownGracefully();
      			worker.shutdownGracefully();
      		}
      	}
      }
  
 

client端代码示例:


      package nettyDemo3;
      import org.omg.PortableServer.POA;
      import io.netty.bootstrap.Bootstrap;
      import io.netty.buffer.ByteBuf;
      import io.netty.buffer.Unpooled;
      import io.netty.channel.Channel;
      import io.netty.channel.ChannelFuture;
      import io.netty.channel.ChannelHandlerAdapter;
      import io.netty.channel.ChannelHandlerContext;
      import io.netty.channel.ChannelInitializer;
      import io.netty.channel.ChannelOption;
      import io.netty.channel.EventLoopGroup;
      import io.netty.channel.nio.NioEventLoopGroup;
      import io.netty.channel.socket.SocketChannel;
      import io.netty.channel.socket.nio.NioSocketChannel;
      import io.netty.handler.codec.LineBasedFrameDecoder;
      import io.netty.handler.codec.string.StringDecoder;
      public class TimeClientHandler extends ChannelHandlerAdapter {
     	private int counter;
     	/**
       * 抛异常会调用此方法
       */
     	@Override
     	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
     		// TODO Auto-generated method stub
     		// super.exceptionCaught(ctx, cause);
      		ctx.close();
      		cause.printStackTrace();
      	}
     	/**
       * 当客户端成功连接上服务端之后会调用此方法
       */
     	@Override
     	public void channelActive(ChannelHandlerContext ctx) throws Exception {
     		// TODO Auto-generated method stub
     		// super.channelActive(ctx);
     		byte[] msg = ("i am clien" + System.getProperty("line.separator")).getBytes();
      		ByteBuf buf = null;
     		for (int i = 0; i < 50; i++) {
      			buf = Unpooled.buffer(msg.length);
      			buf.writeBytes(msg);
      			ctx.writeAndFlush(buf);
      		}
      	}
     	/**
       * 读取服务端回应的消息
       */
     	@Override
     	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
     		// TODO Auto-generated method stub
     		// super.channelRead(ctx, msg);
     		// ByteBuf buf = (ByteBuf) msg;
     		// byte[] bytes = new byte[buf.readableBytes()];
     		// buf.readBytes(bytes);
     		// String body = new String(bytes, "UTF-8");
      		String body = (String) msg;
      		System.out.println(body + "【第" + (++counter) + "次收到服务端的消息】");
      	}
     	public static void main(String[] args) {
     		// 配置客户端端线程组负责读写
      		EventLoopGroup work = new NioEventLoopGroup();
     		try {
     			// 创建客户端的辅助启动类并设置参数
      			Bootstrap bootstrap = new Bootstrap();
      			bootstrap.group(work).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)
       .handler(new ChannelInitializer<SocketChannel>() {
      @Override
      protected void initChannel(SocketChannel ch) throws Exception {
      // TODO Auto-generated method stub
      // 添加解码器
       ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
       ch.pipeline().addLast(new StringDecoder());
       ch.pipeline().addLast(new TimeClientHandler());
       }
       });
     			final String host = "127.0.0.1";
     			final int port = 8080;
     			// 连接服务端
      			ChannelFuture future = bootstrap.connect(host, port).sync();
      			future.channel().closeFuture().sync();
      		} catch (Exception e) {
     			// TODO: handle exception
      		} finally {
     			// 优雅退出,释放线程池资源
      			work.shutdownGracefully();
      		}
      	}
      }
  
 

分别运行客户端和服务端实例,看到控制台输出以下图片中的内容,说明成功解决tcp粘包/拆包问题。

附: netty利用DelimiterBasedFrameDecoder 和 FixedLengthFrameDecoder  也可以按需自定义解码实现粘包/拆包问题


      //添加自定义以$_为分隔符的解码器
      ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
      ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
      //添加固定长度解码器
      ch.pipeline().addLast(new FixedLengthFrameDecoder(13));
  
 

文章来源: blog.csdn.net,作者:血煞风雨城2018,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/qq_31905135/article/details/81736896

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。