当前位置: 首页 > 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

相关文章:

Netty 教程 – 解码器详解

TCP以流的方式进行数据传输&#xff0c;上层的应用为了对消息进行区分&#xff0c;往往采用如下方式 固定消息长度&#xff0c;累计读取到长度和定长LEN的报文后&#xff0c;就认为读取到了个完整的消息&#xff0c;然后将计数器位置重置在读取下一个报文内容将回车换行符作为…...

Allegro如何自动添加测试点操作指导

Allegro如何自动添加测试点操作指导 在做PCB设计的时候,在一些应用场合下需要给PCB上的网络添加测试点,如下图 测试点除了可以手动逐个添加之外,Allegro还支持自动添加测试点,具体操作如下 点击Manufacture点击Testprep...

【CSS】CSS 背景设置 ③ ( 背景位置-长度值设置 | 背景位置-长度值方位值同时设置 )

文章目录一、背景位置-长度值设置二、背景位置-长度值方位值同时设置三、完整代码示例一、背景位置-长度值设置 长度值设置 效果展示 : 设置背景位置为具体值 10px 50px : 粉色区域是盒子的区域 , 图片背景位于盒子位置 x 轴方向 10 像素 , y 轴方向 50 像素 ; 在水平方向上 ,…...

AbTest —— 不同场景下的应用模式

文章目录不同人群眼中的 AbTestAbTest 不同的功能倚重用户关联性弱&#xff0c;经典场景为 Feed - 部门组织形式大多非垂直业务用户关联性强&#xff0c;经典场景为 垂类/工具类APP&#xff1b;部门组织形式大多为垂直业务康为定律-组织决定产品形态不同应用模式下服务构建开机…...

fast-api 一款快速将spring的bean发布成接口并生产对应swagger文档调试的轻量级工具

fast-api简介背景开发痛点:分析需求实战fast-api快速上手1. 引入依赖2. FastApiMapping标记service对象3. swagger2/knife4j 在线测试进阶使用开启调试模式支持指定类或包目录发布如何关闭fast-api自定义fast-api的前缀写在最后简介 fast-api 一款快速将spring的bean(service)发…...

以公益之名 让人类发现数学之美

目录 1.品牌理念高举高打 2.创新赛制 赋能品牌 3.全球化的品牌传播 9月26日&#xff0c;2022阿里巴巴全球数学竞赛获奖名单公布&#xff0c;4座金杯分别由平均年龄25岁&#xff0c;来自美国麻省理工学院、美国布朗大学、北京大学在读数学博士斩获。77位获奖者中00后超五成引热…...

JUC并发编程之HashMap(jdk1.7版本)-底层源码探究

目录 JUC并发编程之HashMap(jdk1.7版本)-底层源码探究 HashMap底层源码 - jdk1.7 基本概念 -采取层层递进&#xff0c;问答式 存储Key-Value的结构 常量和成员变量 构造方法 put方法 inflateTable方法 hash方法 indexFor方法 addEntry方法 resize方法 createEntry…...

QT Q_OBJECT 和 signals/slots

Q_OBJECT宏展开 #define Q_OBJECT \ public: \QT_WARNING_PUSH \Q_OBJECT_NO_OVERRIDE_WARNING \static const QMetaObject staticMetaObject; \virtual const QMetaObject *metaObject() const; \virtual void *qt_metacast(const char *); \virtual int qt_metacall(QMetaOb…...

APM新添加UAVCAN设备

简介 UAVCAN是一种轻量级协议,旨在通过CAN总线在航空航天和机器人应用中实现可靠通信。要实现通信&#xff0c;最基本需要data_type_ id, signature、数据结构、设备程序初始化。 添加设备数据结构文件(.uavcan格式) 1.在以下路径添加设备数据结构文件&#xff0c;根据设备类…...

【C++】string类基本用法

文章目录string类基本用法1. 为什么要学习string类&#xff1f;1.1 C语言中的字符串2. 标准库中的string类2.1 string类2.2 string类的常用接口说明小试牛刀1. 仅仅反转字母2. 字符串中第一个唯一字符3. 字符串中最后一个单词的长度string类基本用法 1. 为什么要学习string类&…...

KDZD耐电压高压击穿强度测试仪

一、技术参数 01、输入电压&#xff1a; 交流 220 V。 02、输出电压&#xff1a; 交流 0--50KV ; 直流 0—50kv 。 03、电器容量&#xff1a;3KVA。 04、高压分级&#xff1a;0—50KV&#xff0c;&#xff08;全程可调&#xff09;。 05、升压速率&#xff1a;0.1KV/s-…...

数组和指针面试题的补充(细的抠jio)

生命是一条艰险的峡谷&#xff0c;只有勇敢的人才能通过。 ——米歇潘 说明&#xff1a;用的vs都是x86的环境&#xff0c;也就是32位平台。 建议&#xff1a;对于难题来说&#xff0c;一定要配合画图来解决问题。 第一题&#xff1a; #include<stdio.h> int…...

Java多线程基础

文章目录Java多线程基础一、什么是进程与线程&#xff1f;二、线程和进程的区别【重点】三、线程的创建方式【重点】1. 继承Thread类2. 实现Runnable接口3. lambda 表达式四、Thread的常见属性线程中断自己定义一个标志位Thread类提供的静态方法线程的状态Java多线程基础 一、…...

爆品分析第5期 | 一条视频带货3700+,这款斋月不锈钢厨具套装火了!

俗话说民以食为天&#xff0c;吃在任何一种文化中都占据重要的位置&#xff0c;要做出一道美味佳肴&#xff0c;除了食材、烹饪者的自身厨艺之外&#xff0c;还少不了一口好锅。新冠疫情以来&#xff0c;全世界范围内的封闭让很多人养成了居家做饭的习惯&#xff0c;不仅为厨具…...

团队管理的七个要点

要掌握团队管理的要点和做好团队管理工作&#xff0c;不是一件容易的事&#xff0c;但也远非想象中那么难。首先&#xff0c;我个人比较推荐所有团队管理者都能阅读下《经理人参阅&#xff1a;团队管理》&#xff08;注意该书仅可其官网获得&#xff09;这本佳作。相信会为你带…...

Go语言容器之map、list和nil

一、map map和C中map一样&#xff0c;里面存放的是key-value键值对在Go中map是引用类型&#xff0c;声明语法&#xff1a;var map变量名 map[key的类型]value的类型package mainimport "fmt"func main() {var mp map[string]intmpls : map[string]int{"one&quo…...

软件测试的案例分析 - 闰年1

&#xff08;这是关于博客质量分的测试 https://www.csdn.net/qc) 我们谈了不少测试的名词, 软件是人写的, 测试计划和测试用例也是人写的, 人总会犯错误。错误发生之后, 总有人问: 为什么这个bug 没有测出来啊?! 我们看看一类简单的bug是如何发生的&#xff0c;以及如何预防…...

【强化学习】强化学习数学基础:值函数近似

值函数近似Value Function ApproximationMotivating examples: curve fittingAlgorithm for state value estimationObjective functionOptimization algorithmsSelection of function approximatorsIllustrative examplesSummary of the storyTheoretical analysisSarsa with …...

JVM系列——Java与线程,介绍线程原理和操作系统的关系

并发不一定要依赖多线程(如PHP中很常见的多进程并发)。 但是在Java里面谈论并发&#xff0c;基本上都与线程脱不开关系。因此我们讲一下从Java线程在虚拟机中的实现。 线程的实现 线程是比进程更轻量级的调度执行单位。 线程的引入&#xff0c;可以把一个进程的资源分配和执行调…...

C++打开文件夹对话框之BROWSEINFO

头文件 #include <shlobj.h> #include <windows.h> #include <stdio.h> using namespace std; 案例 string chooseFile(void) {//用户选择的路径&#xff0c;可以是TCHAR szBuffer[MAX_PATH] {0};然后再使用TCHAR 转char字符串&#xff0c;此处可以直接使…...

Nuxt项目配置、目录结构说明-实战教程基础-Day02

Nuxt项目配置、目录结构说明-实战教程基础-Day02一、Nuxt项目结构1.1资源目录1.2 组件目录1.3 布局目录1.4 中间件目录1.5 页面目录1.6 插件目录1.7 静态文件目录1.8 Store 目录1.9 nuxt.config.js 文件1.10 package.json 文件其他&#xff1a;别名二、项目配置2.1 build2.2 cs…...

单链表的头插,尾插,头删,尾删等操作

前言顺序表要求是具有连续的物理空间&#xff0c;并且数据的话是在这些空间当中是连续的存储。但这样会带来很多问题&#xff0c;比如说在头部或者说中间插入的话&#xff0c;效率不是很高&#xff1b;并且申请空间可能需要扩容&#xff0c;并且越往后一般来说都是异地扩容&…...

Qt扫盲-QProcess理论总结

QProcess理论使用总结一、概述二、使用三、通过 Channel 通道通信四、同步进程API五、注意事项1. 平台特性2. 不能实时读取一、概述 QProcess 其实更多的是与外面进程进行交互的一个工具类&#xff0c;通过这个类来启动外部进程&#xff0c;获取这个进程的标准输出&#xff0c…...

JAVA进阶 —— Steam流

目录 一、 引言 二、 Stream流概述 三、Stream流的使用步骤 1. 获取Stream流 1.1 单列集合 1.2 双列集合 1.3 数组 1.4 零散数据 2. Stream流的中间方法 3. Stream流的终结方法 四、 练习 1. 数据过滤 2. 数据操作 - 按年龄筛选 3. 数据操作 - 演员信息要求…...

Ubuntu Protobuf 安装(测试有效)

安装流程 下载软件 下载自己要安装的版本&#xff1a;https://github.com/protocolbuffers/protobuf 下载源码编译&#xff1a; 系统环境&#xff1a;Ubuntu16&#xff08;其它版本亦可&#xff09;&#xff0c;Protobuf-3.6.1 编译源码 cd protobuf# 当使用 git clone 下来的…...

驱动程序开发:FTP服务器和OpenSSH的移植与搭建、以及一些笔记

目录一、FTP服务器移植与搭建1、在ubuntu下安装vsftpd2、在window下安装FileZilla3、移植vsftpd到开发板上4、Filezilla 连接测试5、注意点二、开发板 OpenSSH 移植与使用1、移植 zlib 库2、移植 openssl 库3、移植 openssh 库4、openssh 使用测试三、关于u-boot上的操作及根文…...

优化改进YOLOv5算法之添加GIoU、DIoU、CIoU、EIoU、Wise-IoU模块(超详细)

目录 1、IoU 1.1 什么是IOU 1.2 IOU代码 2、GIOU 2.1 为什么提出GIOU 2.2 GIoU代码 3 DIoU 3.1 为什么提出DIOU 3.2 DIOU代码 4 CIOU 4.1 为什么提出CIOU 4.2 CIOU代码 5 EIOU 5.1 为什么提出EIOU 5.2 EIOU代码 6 Wise-IoU 7 YOLOv5中添加GIoU、DIoU、CIoU、…...

windows电脑pc如何使用svn获取文档和代码

一、安装svn 下载链接 也可通过其他方式下载 二、使用 2.1 随便找一个文件夹 2.2 点击右键&#xff0c;选择SVN Checkout 2.3输入网址 如当你在网页上访问时地址为https://10.197.78.78/!/#aaa/view/head/bbb 在这里不能直接填入&#xff0c;而是 https://10.197.78.78/sv…...

ROS1学习笔记:tf坐标系广播与监听的编程实现(ubuntu20.04)

参考B站古月居ROS入门21讲&#xff1a;tf坐标系广播与监听的编程实现 基于VMware Ubuntu 20.04 Noetic版本的环境 文章目录一、创建功能包二、创建代码2.1 以C为例2.1.1 配置代码编译规则2.1.2 编译整个工作空间2.1.2 配置环境变量2.1.4 执行代码2.2 以Python为例2.2.1 配置代码…...

​力扣解法汇总1590. 使数组和能被 P 整除

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣 描述&#xff1a; 给你一个正整数数组 nums&#xff0c;请你移除 最短 子数组&#xff08;可以为 …...

嘉兴英文网站建设/营销型网站和普通网站

内部碎片的产生&#xff1a;因为所有的内存分配必须起始于可被 4、8 或 16 整除&#xff08;视处理器体系结构而定&#xff09;的地址或者因为MMU的分页机制的限制&#xff0c;决定内存分配算法仅能把预定大小的内存块分配给客户。假设当某个客户请求一个43字节的内存块时&…...

想自己做点飘纱素材到网站上买/我想做网络推广

conda 1、conda create --name xlr python2.7 --name也可以缩写为-name python2.7是python的版本号,如果不写就默认为装anaconda时python版本 xlr是创建的新的虚拟环境的名字&#xff0c;创建完&#xff0c;可以在装anaconda的目录下找打envs/xlr(或直接find / -name xlr也可…...

上海比较好的网站制作公司/google play下载

在grub customizer 中打开可以查看 遇到一个问题&#xff0c;者几个内核都无法打开&#xff0c;只能打开图2的内核 sudo add-apt-repository ppa:danielrichter2007/grub-customizersudo apt-get updatesudo apt-get install grub-customizer启动前两个内核会有 VFS unable to…...

做金属的网站/成都本地推广平台

很早就听说Charles Petzold的《编码》非常值得一看&#xff0c;特地趁着京东6.18下单&#xff0c;现将阅读收获进行整理&#xff0c;大致分为三篇进行讲解。 第一章 至亲密友 编码的含义&#xff1a;一种传递信息的方式。 思路转换过程&#xff1a;手电筒写字母&#xff08;难…...

兰州网站程序建设/上海网络推广联盟

线程屏障是线程同步的一个方式。线程执行完一个操作后&#xff0c;可能需要等待其他线程也完成某个动作&#xff0c;这时候&#xff0c;当前该线程就会被挂起&#xff0c;直到其他线程也完成了某个操作&#xff0c;最后所有线程被唤醒。屏障主要有三个函数。 int pthread_barr…...

四川建设厅网站查询/怎么制作网站教程手机

ACCESS可在菜单上选择[压缩]来压缩当前正打开的数据库&#xff0c;如是我们就可以通过程序临时添加一个工具条按钮&#xff0c;然后使用 SendKeys 来模拟键盘操作&#xff0c;实现压缩当前数据库&#xff0c;压缩后它会重新打开。函数如下&#xff1a;Function Compact() 添加一…...