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

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

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

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

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

 

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

server端代码示例:


  
  1. package nettyDemo3;
  2. import io.netty.bootstrap.ServerBootstrap;
  3. import io.netty.buffer.ByteBuf;
  4. import io.netty.buffer.Unpooled;
  5. import io.netty.channel.ChannelFuture;
  6. import io.netty.channel.ChannelHandlerAdapter;
  7. import io.netty.channel.ChannelHandlerContext;
  8. import io.netty.channel.ChannelInitializer;
  9. import io.netty.channel.ChannelOption;
  10. import io.netty.channel.EventLoopGroup;
  11. import io.netty.channel.nio.NioEventLoopGroup;
  12. import io.netty.channel.socket.SocketChannel;
  13. import io.netty.channel.socket.nio.NioServerSocketChannel;
  14. import io.netty.handler.codec.LineBasedFrameDecoder;
  15. import io.netty.handler.codec.string.StringDecoder;
  16. public class TimeServerHanler extends ChannelHandlerAdapter {
  17. private int counter; // 计数器
  18. /**
  19. * 抛异常会调用此方法
  20. */
  21. @Override
  22. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  23. // TODO Auto-generated method stub
  24. // super.exceptionCaught(ctx, cause);
  25. cause.printStackTrace();
  26. ctx.close();
  27. }
  28. /**
  29. * 读取客户端回应的消息
  30. */
  31. @Override
  32. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  33. // TODO Auto-generated method stub
  34. // super.channelRead(ctx, msg);
  35. // ByteBuf buf = (ByteBuf) msg;
  36. // byte[] bytes = new byte[buf.readableBytes()];
  37. // buf.readBytes(bytes);
  38. // String body = new String(bytes, "UTF-8");
  39. // System.getProperty("line.separator") 换行符
  40. String body = (String) msg;
  41. System.out.println(body + "【第" + (++counter) + "次收到客户端的消息】");
  42. String result = "i am server" + System.getProperty("line.separator");
  43. ByteBuf buf2 = Unpooled.copiedBuffer(result.getBytes());
  44. ctx.write(buf2);
  45. }
  46. /**
  47. * 读取完成之后会调用此方法
  48. */
  49. @Override
  50. public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  51. // TODO Auto-generated method stub
  52. // super.channelReadComplete(ctx);
  53. ctx.flush();
  54. System.out.println("读取完成");
  55. }
  56. public static void main(String[] args) {
  57. // 配置服务端线程组,一个负责连接 ,一个负责读写
  58. EventLoopGroup boss = new NioEventLoopGroup();
  59. EventLoopGroup worker = new NioEventLoopGroup();
  60. try {
  61. // 创建服务端辅助启动类并设置参数
  62. ServerBootstrap bootstrap = new ServerBootstrap();
  63. bootstrap.group(boss, worker).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)
  64. .handler(new LoggingHandler(LogLevel.INFO))
  65. .childHandler(new ChannelInitializer<SocketChannel>() {
  66. @Override
  67. protected void initChannel(SocketChannel ch) throws Exception {
  68. // TODO Auto-generated method stub
  69. // 添加回车换行符解码器
  70. ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
  71. ch.pipeline().addLast(new StringDecoder());
  72. ch.pipeline().addLast(new TimeServerHanler());
  73. }
  74. });
  75. int inetPort = 8080;
  76. // 绑定端口,并开始阻塞等待客户端的连接
  77. ChannelFuture f = bootstrap.bind(inetPort).sync();
  78. f.channel().closeFuture().sync();
  79. } catch (Exception e) {
  80. e.printStackTrace();
  81. } finally {
  82. // 优雅退出,释放线程池资源
  83. boss.shutdownGracefully();
  84. worker.shutdownGracefully();
  85. }
  86. }
  87. }

 

client端代码示例:


  
  1. package nettyDemo3;
  2. import org.omg.PortableServer.POA;
  3. import io.netty.bootstrap.Bootstrap;
  4. import io.netty.buffer.ByteBuf;
  5. import io.netty.buffer.Unpooled;
  6. import io.netty.channel.Channel;
  7. import io.netty.channel.ChannelFuture;
  8. import io.netty.channel.ChannelHandlerAdapter;
  9. import io.netty.channel.ChannelHandlerContext;
  10. import io.netty.channel.ChannelInitializer;
  11. import io.netty.channel.ChannelOption;
  12. import io.netty.channel.EventLoopGroup;
  13. import io.netty.channel.nio.NioEventLoopGroup;
  14. import io.netty.channel.socket.SocketChannel;
  15. import io.netty.channel.socket.nio.NioSocketChannel;
  16. import io.netty.handler.codec.LineBasedFrameDecoder;
  17. import io.netty.handler.codec.string.StringDecoder;
  18. public class TimeClientHandler extends ChannelHandlerAdapter {
  19. private int counter;
  20. /**
  21. * 抛异常会调用此方法
  22. */
  23. @Override
  24. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  25. // TODO Auto-generated method stub
  26. // super.exceptionCaught(ctx, cause);
  27. ctx.close();
  28. cause.printStackTrace();
  29. }
  30. /**
  31. * 当客户端成功连接上服务端之后会调用此方法
  32. */
  33. @Override
  34. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  35. // TODO Auto-generated method stub
  36. // super.channelActive(ctx);
  37. byte[] msg = ("i am clien" + System.getProperty("line.separator")).getBytes();
  38. ByteBuf buf = null;
  39. for (int i = 0; i < 50; i++) {
  40. buf = Unpooled.buffer(msg.length);
  41. buf.writeBytes(msg);
  42. ctx.writeAndFlush(buf);
  43. }
  44. }
  45. /**
  46. * 读取服务端回应的消息
  47. */
  48. @Override
  49. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  50. // TODO Auto-generated method stub
  51. // super.channelRead(ctx, msg);
  52. // ByteBuf buf = (ByteBuf) msg;
  53. // byte[] bytes = new byte[buf.readableBytes()];
  54. // buf.readBytes(bytes);
  55. // String body = new String(bytes, "UTF-8");
  56. String body = (String) msg;
  57. System.out.println(body + "【第" + (++counter) + "次收到服务端的消息】");
  58. }
  59. public static void main(String[] args) {
  60. // 配置客户端端线程组负责读写
  61. EventLoopGroup work = new NioEventLoopGroup();
  62. try {
  63. // 创建客户端的辅助启动类并设置参数
  64. Bootstrap bootstrap = new Bootstrap();
  65. bootstrap.group(work).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)
  66. .handler(new ChannelInitializer<SocketChannel>() {
  67. @Override
  68. protected void initChannel(SocketChannel ch) throws Exception {
  69. // TODO Auto-generated method stub
  70. // 添加解码器
  71. ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
  72. ch.pipeline().addLast(new StringDecoder());
  73. ch.pipeline().addLast(new TimeClientHandler());
  74. }
  75. });
  76. final String host = "127.0.0.1";
  77. final int port = 8080;
  78. // 连接服务端
  79. ChannelFuture future = bootstrap.connect(host, port).sync();
  80. future.channel().closeFuture().sync();
  81. } catch (Exception e) {
  82. // TODO: handle exception
  83. } finally {
  84. // 优雅退出,释放线程池资源
  85. work.shutdownGracefully();
  86. }
  87. }
  88. }

 

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

 

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


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

 

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

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

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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