当前位置: 首页 > news >正文

Netty 教程 – 解码器详解

TCP以流的方式进行数据传输,上层的应用为了对消息进行区分,往往采用如下方式

  • 固定消息长度,累计读取到长度和定长LEN的报文后,就认为读取到了个完整的消息,然后将计数器位置重置在读取下一个报文内容
  • 将回车换行符作为消息结束符\r\n,列如FTP协议,这种方式在文本中应用比较广泛
  • 将特殊分隔符作为消息结束符标志位,回车换行符就是一个特殊结束分隔符(DelimiterBasedFrameDecoder)
  • 通过在消息头定义一个长度字段来标示消息的总长度(FixedLengthFrameDecoder)

Netty对以上4种做个统一抽象封装,提供了四种不同解码器来解决对应问题,使用起来也非常的方便,了解了它们,我们就不需要自己对读取的报文人工解码,也不需要考虑TCP粘包和拆包的问题了…

Delimiter自定义分隔符

我将公共的部分做了一层抽离,定义成常量方便调用

public interface EchoConstant {String SEPARATOR = "$_";//特殊分割符号,DelimiterBasedFrameDecoder使用Integer ECHO_DELIMITER_PORT = 4040;Integer ECHO_LENGTH_PORT = 5050;String HOST = "127.0.0.1";Integer FRAME_LENGTH = 10;//固定消息长度,FixedLengthFrameDecoder使用
}

定义EchoDelimiterServer,毫无疑问大部分代码和以前类似,区别是多了一个日志输出以及DelimiterBasedFrameDecoder的使用

划重点:在做开发调试的时候,我们可以使用Netty为我们提供的LoggingHandler输出日志

public static void bind(int port) {EventLoopGroup masterGroup = new NioEventLoopGroup();//线程组,含一组NIO线程,专门用来处理网络事件EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap bootstrap = new ServerBootstrap();//NIO服务端启动辅助类bootstrap.group(masterGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel channel) throws Exception {ByteBuf delimiter = Unpooled.copiedBuffer(EchoConstant.SEPARATOR.getBytes());channel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));channel.pipeline().addLast(new StringDecoder());channel.pipeline().addLast(new EchoServerHandler());}});//绑定端口,同步等待成功,System.out.println("绑定端口,同步等待成功......");ChannelFuture future = bootstrap.bind(port).sync();//等待服务端监听端口关闭future.channel().closeFuture().sync();System.out.println("等待服务端监听端口关闭......");} catch (Exception e) {e.printStackTrace();} finally {//优雅退出释放线程池masterGroup.shutdownGracefully();workerGroup.shutdownGracefully();System.out.println("优雅退出释放线程池......");}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {String body = (String) msg;System.out.println("EchoDelimiterServer 接收到的消息 :" + body + "; 当前统计:" + ++counter);body = body + EchoConstant.SEPARATOR;//在消息后面加上特殊分隔符ByteBuf echo = Unpooled.copiedBuffer(body.getBytes());ctx.writeAndFlush(echo);//消息写出
}

定义EchoDelimiterClient

public static void connect(String host, int port) {EventLoopGroup group = new NioEventLoopGroup();Bootstrap bootstrap = new Bootstrap();ChannelFuture future = null;try {bootstrap.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel channel) throws Exception {ByteBuf delimiter = Unpooled.copiedBuffer(EchoConstant.SEPARATOR.getBytes());channel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));channel.pipeline().addLast(new StringDecoder());channel.pipeline().addLast(new EchoClientHandler());}});//发起异步请求future = bootstrap.connect(host, port).sync();//等待客户端链路关闭future.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {group.shutdownGracefully();}
}

创建EchoClientHandler继承ChannelHandlerAdapter,重写读取和写出事件

@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {for (int i = 0; i < 10; i++) {ctx.writeAndFlush(Unpooled.copiedBuffer(ECHO_REQ.getBytes()));}
}@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {String body = (String) msg;System.out.println("EchoDelimiterClient 接收到的消息 :" + body + "; 当前统计:" + ++counter);
}

试验一把

分别启动EchoDelimiterServerEchoDelimiterClient,输出如下日志

绑定端口,同步等待成功......
九月 04, 2017 10:41:27 下午 io.netty.handler.logging.LoggingHandler channelRegistered
信息: [id: 0x3b1849e8] REGISTERED
九月 04, 2017 10:41:27 下午 io.netty.handler.logging.LoggingHandler bind
信息: [id: 0x3b1849e8] BIND: 0.0.0.0/0.0.0.0:4040
九月 04, 2017 10:41:27 下午 io.netty.handler.logging.LoggingHandler channelActive
信息: [id: 0x3b1849e8, /0:0:0:0:0:0:0:0:4040] ACTIVE
九月 04, 2017 10:41:33 下午 io.netty.handler.logging.LoggingHandler channelRead
信息: [id: 0x3b1849e8, /0:0:0:0:0:0:0:0:4040] RECEIVED: [id: 0xa45511cd, /127.0.0.1:50226 => /127.0.0.1:4040]
EchoDelimiterServer 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:1
EchoDelimiterServer 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:2
EchoDelimiterServer 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:3
EchoDelimiterServer 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:4
EchoDelimiterServer 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:5
EchoDelimiterServer 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:6
EchoDelimiterServer 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:7
EchoDelimiterServer 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:8
EchoDelimiterServer 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:9
EchoDelimiterServer 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:10------------------------------------------------------------------------------------------------EchoDelimiterClient 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:1
EchoDelimiterClient 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:2
EchoDelimiterClient 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:3
EchoDelimiterClient 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:4
EchoDelimiterClient 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:5
EchoDelimiterClient 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:6
EchoDelimiterClient 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:7
EchoDelimiterClient 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:8
EchoDelimiterClient 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:9
EchoDelimiterClient 接收到的消息 :Hi , Levin .Welcome to Netty.; 当前统计:10
http://www.lryc.cn/news/37168.html

相关文章:

  • Allegro如何自动添加测试点操作指导
  • 【CSS】CSS 背景设置 ③ ( 背景位置-长度值设置 | 背景位置-长度值方位值同时设置 )
  • AbTest —— 不同场景下的应用模式
  • fast-api 一款快速将spring的bean发布成接口并生产对应swagger文档调试的轻量级工具
  • 以公益之名 让人类发现数学之美
  • JUC并发编程之HashMap(jdk1.7版本)-底层源码探究
  • QT Q_OBJECT 和 signals/slots
  • APM新添加UAVCAN设备
  • 【C++】string类基本用法
  • KDZD耐电压高压击穿强度测试仪
  • 数组和指针面试题的补充(细的抠jio)
  • Java多线程基础
  • 爆品分析第5期 | 一条视频带货3700+,这款斋月不锈钢厨具套装火了!
  • 团队管理的七个要点
  • Go语言容器之map、list和nil
  • 软件测试的案例分析 - 闰年1
  • 【强化学习】强化学习数学基础:值函数近似
  • JVM系列——Java与线程,介绍线程原理和操作系统的关系
  • C++打开文件夹对话框之BROWSEINFO
  • Nuxt项目配置、目录结构说明-实战教程基础-Day02
  • 单链表的头插,尾插,头删,尾删等操作
  • Qt扫盲-QProcess理论总结
  • JAVA进阶 —— Steam流
  • Ubuntu Protobuf 安装(测试有效)
  • 驱动程序开发:FTP服务器和OpenSSH的移植与搭建、以及一些笔记
  • 优化改进YOLOv5算法之添加GIoU、DIoU、CIoU、EIoU、Wise-IoU模块(超详细)
  • windows电脑pc如何使用svn获取文档和代码
  • ROS1学习笔记:tf坐标系广播与监听的编程实现(ubuntu20.04)
  • ​力扣解法汇总1590. 使数组和能被 P 整除
  • Spring源码阅读(基础)