netty权威指南学习笔记五——分隔符和定长解码器的应用
TCP以流的方式进行数据传输,上层应用协议为了对消息进行区分,通常采用以下4中方式:
- 消息长度固定,累计读取到长度综合为定长LEN的报文后,就认为读取到了一个完整的消息,将计数器置位,重新开始读取下一个数据报;
- 将回车换行符作为消息结束符,例如FTP协议,这种方式在文本协议中应用比较广泛;
- 将特殊的分隔符作为消息的结束标志,回车换行符就是一种特殊的分隔符;
- 通过在消息头中定义长度字段来标识消息的总长度。
DelimiterBaseFrameDecoder——分隔符解码器,FixedLengthFrameDecoder——定长解码器
下面我们采用#为分隔符进行代码练习运行。
EchoServer服务端代码
1 package com.decoder; 2 3 import io.netty.bootstrap.ServerBootstrap; 4 import io.netty.buffer.ByteBuf; 5 import io.netty.buffer.Unpooled; 6 import io.netty.channel.ChannelFuture; 7 import io.netty.channel.ChannelInitializer; 8 import io.netty.channel.ChannelOption; 9 import io.netty.channel.nio.NioEventLoopGroup; 10 import io.netty.channel.socket.SocketChannel; 11 import io.netty.channel.socket.nio.NioServerSocketChannel; 12 import io.netty.handler.codec.DelimiterBasedFrameDecoder; 13 import io.netty.handler.codec.string.StringDecoder; 14 import io.netty.handler.logging.LogLevel; 15 import io.netty.handler.logging.LoggingHandler; 16 17 public class EchoServer { 18 public void bind(int port) throws InterruptedException { 19 NioEventLoopGroup bossGroup = new NioEventLoopGroup(); 20 NioEventLoopGroup workGroup = new NioEventLoopGroup(); 21 try { 22 ServerBootstrap b = new ServerBootstrap(); 23 b.group(bossGroup,workGroup) 24 .channel(NioServerSocketChannel.class) 25 .option(ChannelOption.SO_BACKLOG,100) 26 .childHandler(new LoggingHandler(LogLevel.INFO)) 27 .childHandler(new ChannelInitializer<SocketChannel>() { 28 @Override 29 protected void initChannel(SocketChannel socketChannel) throws Exception { 30 ByteBuf delimiter = Unpooled.copiedBuffer("#".getBytes());//创建一个分隔符,确定为结束标志 31 socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimiter)) 32 .addLast(new StringDecoder()) 33 .addLast(new EchoServerHandler()); 34 } 35 }); 36 // 绑定端口,同步等待成功 37 ChannelFuture f = b.bind(port).sync(); 38 // 等待服务端监听端口关闭 39 f.channel().closeFuture().sync(); 40 } finally { 41 bossGroup.shutdownGracefully(); 42 workGroup.shutdownGracefully(); 43 } 44 } 45 public static void main(String[] args) throws InterruptedException { 46 int port = 8080; 47 if(args.length>0&&args!=null){ 48 port = Integer.parseInt(args[0]); 49 } 50 new EchoServer().bind(port); 51 52 } 53 }
服务端处理IO代码
1 package com.decoder; 2 3 import io.netty.buffer.ByteBuf; 4 import io.netty.buffer.Unpooled; 5 import io.netty.channel.ChannelHandlerContext; 6 import io.netty.channel.ChannelInboundHandlerAdapter; 7 8 public class EchoServerHandler extends ChannelInboundHandlerAdapter { 9 int count; 10 @Override 11 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 12 String body = (String) msg; 13 System.out.println("This is"+ ++count +" times server receive client request."); 14 body += "#"; 15 ByteBuf echo = Unpooled.copiedBuffer(body.getBytes()); 16 ctx.writeAndFlush(echo); 17 } 18 19 @Override 20 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 21 ctx.flush(); 22 } 23 24 @Override 25 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 26 ctx.close(); 27 } 28 }
客户端发送消息代码
1 package com.decoder; 2 3 import io.netty.bootstrap.Bootstrap; 4 import io.netty.buffer.ByteBuf; 5 import io.netty.buffer.Unpooled; 6 import io.netty.channel.ChannelFuture; 7 import io.netty.channel.ChannelInitializer; 8 import io.netty.channel.ChannelOption; 9 import io.netty.channel.nio.NioEventLoopGroup; 10 import io.netty.channel.socket.SocketChannel; 11 import io.netty.channel.socket.nio.NioSocketChannel; 12 import io.netty.handler.codec.DelimiterBasedFrameDecoder; 13 import io.netty.handler.codec.string.StringDecoder; 14 15 public class EchoClient { 16 public void connection(int port,String host) throws InterruptedException { 17 NioEventLoopGroup workGroup = new NioEventLoopGroup(); 18 try { 19 Bootstrap b = new Bootstrap(); 20 b.group(workGroup) 21 .channel(NioSocketChannel.class) 22 .option(ChannelOption.TCP_NODELAY,true) 23 .handler(new ChannelInitializer<SocketChannel>() { 24 @Override 25 protected void initChannel(SocketChannel socketChannel) throws Exception { 26 ByteBuf delimiter = Unpooled.copiedBuffer("#".getBytes()); 27 socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimiter)) 28 .addLast(new StringDecoder()) 29 .addLast(new EchoClientHandler()); 30 // 31 } 32 }); 33 // 发起异步连接操作 34 ChannelFuture f = b.connect(host,port).sync(); 35 // 等待客户端链路关闭 36 f.channel().closeFuture().sync(); 37 } finally { 38 workGroup.shutdownGracefully(); 39 } 40 } 41 public static void main(String[] args) throws InterruptedException { 42 int port = 8080; 43 if(args.length>0&&args!=null){ 44 System.out.println(args[0]); 45 port = Integer.parseInt(args[0]); 46 } 47 new EchoClient().connection(port,"127.0.0.1"); 48 } 49 }
客户端处理IO代码
1 package com.decoder; 2 3 import io.netty.buffer.Unpooled; 4 import io.netty.channel.ChannelHandlerContext; 5 import io.netty.channel.ChannelInboundHandlerAdapter; 6 7 public class EchoClientHandler extends ChannelInboundHandlerAdapter { 8 private int count; 9 static final String ECHO_REQ = "hello,zuixiaoyao,welcome here!#"; 10 11 @Override 12 public void channelActive(ChannelHandlerContext ctx) throws Exception { 13 for(int i=0;i<10;i++){ 14 ctx.writeAndFlush(Unpooled.copiedBuffer(ECHO_REQ.getBytes())); 15 } 16 } 17 18 @Override 19 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 20 String body = (String) msg; 21 System.out.println("this is client receive msg"+ ++count +"times:【"+body+"】"); 22 } 23 24 @Override 25 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 26 super.channelReadComplete(ctx); 27 } 28 29 @Override 30 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 31 super.exceptionCaught(ctx, cause); 32 } 33 }
运行结果
服务端
客户端
若采用定长解码器,运行上面代码看看会发生什么,我们只需要对上面服务器中解码器换为定长解码器即可,解码器最大长度设置为20,看看
修改的服务端代码如下:
1 @Override 2 protected void initChannel(SocketChannel socketChannel) throws Exception { 3 ByteBuf delimiter = Unpooled.copiedBuffer("#".getBytes());//创建一个分隔符,确定为结束标志 4 socketChannel.pipeline() 5 // .addLast(new DelimiterBasedFrameDecoder(1024,delimiter)) 6 // 修改为定长解码器 7 .addLast(new FixedLengthFrameDecoder(20)) 8 .addLast(new StringDecoder()) 9 .addLast(new EchoServerHandler()); 10 }
运行后如下:
服务端结果
客户端结果
我们发现所有运行返回的代码都不超过20字符。这就是按照定长解析的,但是解析的比较乱,具体的原理还需深入学习后才知道,暂时不表。
按书上的操作,输入一行超过20字符的命令请求时,只返回一个20字符定长的数据显示。
转载于:https://www.cnblogs.com/xiaoyao-001/p/9346628.html
netty权威指南学习笔记五——分隔符和定长解码器的应用相关推荐
- netty权威指南 学习笔记http
序 李林峰的<netty权威指南>,从Java的NIO开始介绍,后面介绍TCP粘包拆包.中级篇介绍编解码技术. 第10章介绍了HTTP及netty HTTP+XML的技术. 因为xml实际 ...
- netty权威指南学习笔记三——TCP粘包/拆包之粘包现象
TCP是个流协议,流没有一定界限.TCP底层不了解业务,他会根据TCP缓冲区的实际情况进行包划分,在业务上,一个业务完整的包,可能会被TCP底层拆分为多个包进行发送,也可能多个小包组合成一个大的数据包 ...
- netty权威指南学习笔记一——NIO入门(4)AIO
NIO2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现.异步通道提供以下两种方式获取操作结果. 1.通过java.util.concurrent.Future 类来表示异步操 ...
- JavaScript 权威指南-学习笔记(一)
本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! JavaScript 权威指南-学习笔记 ...
- 《Netty权威指南》笔记 —— 第二十、二十一、二十二, 二十三章
<Netty权威指南>笔记--Netty高级特性 第20章 Netty架构剖析 Reactor通信调度层 职责链 ChannelPipeline 业务逻辑编排层 关键架构质量属性 高性能 ...
- Hadoop权威指南学习笔记三
HDFS简单介绍 声明:本文是本人基于Hadoop权威指南学习的一些个人理解和笔记,仅供学习參考.有什么不到之处还望指出,一起学习一起进步. 转载请注明:http://blog.csdn.net/my ...
- Hadoop权威指南学习笔记一
Hadoop简单介绍 声明:本文是本人基于Hadoop权威指南学习的一些个人理解和笔记,仅供学习參考,有什么不到之处还望指出.一起学习一起进步. 转载请注明:http://blog.csdn.net/ ...
- ZeroC Ice权威指南-学习笔记1——hello world
前言 ZeroC Ice是一款很好的RPC框架,性能极好.但是参考文档不足是其一大问题,这也影响了它的传播.<ZeroC Ice权威指南>是唯一的中文教材,但写的不尽如人意,作为入门教材, ...
- Javascript权威指南学习笔记一:数据类型
决定从最基础的开始学JavaScript,最近看了<<Javascript权威指南>>第3章,记些笔记备忘. 本章一个重点是类型.按我的理解应该如下表所示: 复合类型中,关联数 ...
最新文章
- PubChem的Python接口PubChemPy
- Android 停止调试程序
- python安装教程win8-python 2.7在win8.1上安装的方法
- Spring详解:WebServlet 中不能注入Bean对象
- linux下oracle修改最大连接数,linux修改TCP最大连接数
- 处理移动端pdf展示问题
- 【HNOI2017】礼物
- java图片色阶调整、亮度调整
- xp的guest访问
- Jupyter notebook最简原型界面设计 - ipywidgets与lineup_widget
- 机刷实名认证软件_代刷网已上架抖音代实名认证和抖音音乐人认证
- Paper | Multitask learning
- vue-router实现history模式配置
- linux操作系统版本_史上最全的Linux 各个发行版本的优点、缺点、发展史介绍
- Si9000计算嘉立创JLC04161H-7628(推荐/免费)方法
- 我遇见了一个问题求帮助
- Parsing error processing resource path jndi:/localhost/JOA/WEB-INF/struts-config
- 剑指offer笔记(六)字符串空格替换
- Flask 微信公众号开发
- 前置知识-辛几何与辛代数、欧式几何与辛几何、Hamilton量
热门文章
- hibernate中List一对多映射关系详解
- 跟我学Spring3(8.2):对ORM的支持之集成Hibernate3
- Struts2 Result详解
- 不该被遗忘的nodeName、nodeValue和nodeType!
- Struts2中表单与Action传递数据三种方式
- golang中的数字签名
- 已解决:大家使用原子哥的延时函数delay_ms,delay_us会出现进入延时函数出不来的情况
- springmvc十五:数据输出
- python六十五:描述符(__get__, __set__, __delete__)
- spring boot一:入门