netty权威指南学习笔记五——分隔符和定长解码器的应用
TCP以流的方式进行数据传输,上层应用协议为了对消息进行区分,通常采用以下4中方式:
- 消息长度固定,累计读取到长度综合为定长LEN的报文后,就认为读取到了一个完整的消息,将计数器置位,重新开始读取下一个数据报;
- 将回车换行符作为消息结束符,例如FTP协议,这种方式在文本协议中应用比较广泛;
- 将特殊的分隔符作为消息的结束标志,回车换行符就是一种特殊的分隔符;
- 通过在消息头中定义长度字段来标识消息的总长度。
DelimiterBaseFrameDecoder——分隔符解码器,FixedLengthFrameDecoder——定长解码器
下面我们采用#为分隔符进行代码练习运行。
EchoServer服务端代码
- package com.decoder;
- import io.netty.bootstrap.ServerBootstrap;
- import io.netty.buffer.ByteBuf;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.ChannelFuture;
- import io.netty.channel.ChannelInitializer;
- import io.netty.channel.ChannelOption;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.SocketChannel;
- import io.netty.channel.socket.nio.NioServerSocketChannel;
- import io.netty.handler.codec.DelimiterBasedFrameDecoder;
- import io.netty.handler.codec.string.StringDecoder;
- import io.netty.handler.logging.LogLevel;
- import io.netty.handler.logging.LoggingHandler;
- public class EchoServer {
- public void bind(int port) throws InterruptedException {
- NioEventLoopGroup bossGroup = new NioEventLoopGroup();
- NioEventLoopGroup workGroup = new NioEventLoopGroup();
- try {
- ServerBootstrap b = new ServerBootstrap();
- b.group(bossGroup,workGroup)
- .channel(NioServerSocketChannel.class)
- .option(ChannelOption.SO_BACKLOG,100)
- .childHandler(new LoggingHandler(LogLevel.INFO))
- .childHandler(new ChannelInitializer<SocketChannel>() {
- @Override
- protected void initChannel(SocketChannel socketChannel) throws Exception {
- ByteBuf delimiter = Unpooled.copiedBuffer("#".getBytes());//创建一个分隔符,确定为结束标志
- socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimiter))
- .addLast(new StringDecoder())
- .addLast(new EchoServerHandler());
- }
- });
- // 绑定端口,同步等待成功
- ChannelFuture f = b.bind(port).sync();
- // 等待服务端监听端口关闭
- f.channel().closeFuture().sync();
- } finally {
- bossGroup.shutdownGracefully();
- workGroup.shutdownGracefully();
- }
- }
- public static void main(String[] args) throws InterruptedException {
- int port = 8080;
- if(args.length>0&&args!=null){
- port = Integer.parseInt(args[0]);
- }
- new EchoServer().bind(port);
- }
- }
服务端处理IO代码
- package com.decoder;
- import io.netty.buffer.ByteBuf;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.ChannelInboundHandlerAdapter;
- public class EchoServerHandler extends ChannelInboundHandlerAdapter {
- int count;
- @Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
- String body = (String) msg;
- System.out.println("This is"+ ++count +" times server receive client request.");
- body += "#";
- ByteBuf echo = Unpooled.copiedBuffer(body.getBytes());
- ctx.writeAndFlush(echo);
- }
- @Override
- public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
- ctx.flush();
- }
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- ctx.close();
- }
- }
客户端发送消息代码
- package com.decoder;
- import io.netty.bootstrap.Bootstrap;
- import io.netty.buffer.ByteBuf;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.ChannelFuture;
- import io.netty.channel.ChannelInitializer;
- import io.netty.channel.ChannelOption;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.SocketChannel;
- import io.netty.channel.socket.nio.NioSocketChannel;
- import io.netty.handler.codec.DelimiterBasedFrameDecoder;
- import io.netty.handler.codec.string.StringDecoder;
- public class EchoClient {
- public void connection(int port,String host) throws InterruptedException {
- NioEventLoopGroup workGroup = new NioEventLoopGroup();
- try {
- Bootstrap b = new Bootstrap();
- b.group(workGroup)
- .channel(NioSocketChannel.class)
- .option(ChannelOption.TCP_NODELAY,true)
- .handler(new ChannelInitializer<SocketChannel>() {
- @Override
- protected void initChannel(SocketChannel socketChannel) throws Exception {
- ByteBuf delimiter = Unpooled.copiedBuffer("#".getBytes());
- socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimiter))
- .addLast(new StringDecoder())
- .addLast(new EchoClientHandler());
- //
- }
- });
- // 发起异步连接操作
- ChannelFuture f = b.connect(host,port).sync();
- // 等待客户端链路关闭
- f.channel().closeFuture().sync();
- } finally {
- workGroup.shutdownGracefully();
- }
- }
- public static void main(String[] args) throws InterruptedException {
- int port = 8080;
- if(args.length>0&&args!=null){
- System.out.println(args[0]);
- port = Integer.parseInt(args[0]);
- }
- new EchoClient().connection(port,"127.0.0.1");
- }
- }
客户端处理IO代码
- package com.decoder;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.ChannelInboundHandlerAdapter;
- public class EchoClientHandler extends ChannelInboundHandlerAdapter {
- private int count;
- static final String ECHO_REQ = "hello,zuixiaoyao,welcome here!#";
- @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("this is client receive msg"+ ++count +"times:【"+body+"】");
- }
- @Override
- public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
- super.channelReadComplete(ctx);
- }
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- super.exceptionCaught(ctx, cause);
- }
- }
运行结果
服务端
客户端
若采用定长解码器,运行上面代码看看会发生什么,我们只需要对上面服务器中解码器换为定长解码器即可,解码器最大长度设置为20,看看
修改的服务端代码如下:
- @Override
- protected void initChannel(SocketChannel socketChannel) throws Exception {
- ByteBuf delimiter = Unpooled.copiedBuffer("#".getBytes());//创建一个分隔符,确定为结束标志
- socketChannel.pipeline()
- // .addLast(new DelimiterBasedFrameDecoder(1024,delimiter))
- // 修改为定长解码器
- .addLast(new FixedLengthFrameDecoder(20))
- .addLast(new StringDecoder())
- .addLast(new EchoServerHandler());
- }
运行后如下:
服务端结果
客户端结果
我们发现所有运行返回的代码都不超过20字符。这就是按照定长解析的,但是解析的比较乱,具体的原理还需深入学习后才知道,暂时不表。
按书上的操作,输入一行超过20字符的命令请求时,只返回一个20字符定长的数据显示。
netty权威指南学习笔记五——分隔符和定长解码器的应用的更多相关文章
- netty权威指南学习笔记六——编解码技术之MessagePack
编解码技术主要应用在网络传输中,将对象比如BOJO进行编解码以利于网络中进行传输.平常我们也会将编解码说成是序列化/反序列化 定义:当进行远程跨进程服务调用时,需要把被传输的java对象编码为字节数组 ...
- netty权威指南学习笔记三——TCP粘包/拆包之粘包现象
TCP是个流协议,流没有一定界限.TCP底层不了解业务,他会根据TCP缓冲区的实际情况进行包划分,在业务上,一个业务完整的包,可能会被TCP底层拆分为多个包进行发送,也可能多个小包组合成一个大的数据包 ...
- netty权威指南学习笔记二——netty入门应用
经过了前面的NIO基础知识准备,我们已经对NIO有了较大了解,现在就进入netty的实际应用中来看看吧.重点体会整个过程. 按照权威指南写程序的过程中,发现一些问题:当我们在定义handler继承Ch ...
- netty权威指南学习笔记八——编解码技术之JBoss Marshalling
JBoss Marshalling 是一个java序列化包,对JDK默认的序列化框架进行了优化,但又保持跟java.io.Serializable接口的兼容,同时增加了一些可调参数和附加特性,这些参数 ...
- netty权威指南学习笔记一——NIO入门(1)BIO
公司的一些项目采用了netty框架,为了加速适应公司开发,本博主认真学习netty框架,前一段时间主要看了看书,发现编程这东西,不上手还是觉得差点什么,于是为了加深理解,深入学习,本博主还是决定多动手 ...
- netty权威指南学习笔记七——编解码技术之GoogleProtobuf
首先我们来看一下protobuf的优点: 谷歌长期使用成熟度高: 跨语言支持多种语言如:C++,java,Python: 编码后消息更小,更利于存储传输: 编解码性能高: 支持不同协议版本的兼容性: ...
- netty权威指南学习笔记四——TCP粘包/拆包之粘包问题解决
发生了粘包,我们需要将其清晰的进行拆包处理,这里采用LineBasedFrameDecoder来解决 LineBasedFrameDecoder的工作原理是它依次遍历ByteBuf中的可读字节,判断看 ...
- netty权威指南学习笔记一——NIO入门(3)NIO
经过前面的铺垫,在这一节我们进入NIO编程,NIO弥补了原来同步阻塞IO的不足,他提供了高速的.面向块的I/O,NIO中加入的Buffer缓冲区,体现了与原I/O的一个重要区别.在面向流的I/O中,可 ...
- IDA Pro 权威指南学习笔记(五) - IDA 主要的数据显示窗口
在默认配置下,IDA(从 6.1 版开始)会在对新二进制文件的初始加载和分析阶段创建 7 个显示窗口 3 个立即可见的窗口分别为 IDA-View 窗口.函数窗口和消息输出窗口 可以通过 View - ...
随机推荐
- free to monitor your sqlserver easy and safe and ...
Unlike AWR in Oracle, Sqlserver does not have offical way to make history performance information fo ...
- 移动端300毫秒事件响应延迟解决方法[fastclick]
vue-cli[2.x]中: 安装 npm install fastclick --save 使用: 在main.js中 :先 import fastClick from 'fastclick' 然后 ...
- AtCoder agc007_d Shik and Game
洛谷题目页面传送门 & AtCoder题目页面传送门 有\(1\)根数轴,Shik初始在位置\(0\).数轴上有\(n\)只小熊,第\(i\)只在位置\(a_i\).Shik每秒可以向左移动\ ...
- Node.js之EventEmiter
参考: 1. Node.js之EventEmiter讲解 2. Node.js之events事件 3. 在线运行node.js代码 Node.js主要API使用异步事件驱动模型,异步I/O操作完成时, ...
- 运行cmd直接进入指定目录下的命令
新建一个.bat批处理文件,文件命令为@ECHO OFF cmd /k cd /d c:data 运行该批处理文件cmd就可进入指定的文件夹,感兴趣的朋友可以参考下啊 新建一个.bat批处理文件,文件 ...
- 三 HTML框架标签
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 入门学习C链接
参考链接:http://c.biancheng.net/view/465.html 在里面链接下载了:code:block,还有C语言入门的PDF文件. 常看网站:https://www.cnblog ...
- java并发队列
阻塞队列 常见的阻塞队列有ArrayBlockingQueue,LinkedBlockingDeque,LinkedBlockingQueue,这些队列有界且可以阻塞线程 ArrayBlockingQ ...
- Linux和云供应商Red Hat被IBM以34亿美元的价格收购
导读 今天的主题包括IBM以340亿美元收购Red Hat,人性化是使人工智能成功的关键.两家公司于10月28日宣布,IBM正以340亿美元的价格收购Linux和云技术供应商Red Hat,以期改变云 ...
- 第2节 storm路由器项目开发:1 - 7、网络路由器项目
网安需求: 1:IFTTT:随着物联网的兴起,if this then that .如果出现这种情况,那么及时反映做出对应的操作. 判断手机号黑白名单,mac地址黑白名单.如果是碰到手机号或者mac地 ...