TCP以流的方式进行数据传输,上层应用协议为了对消息进行区分,通常采用以下4中方式:

  1. 消息长度固定,累计读取到长度综合为定长LEN的报文后,就认为读取到了一个完整的消息,将计数器置位,重新开始读取下一个数据报;
  2. 将回车换行符作为消息结束符,例如FTP协议,这种方式在文本协议中应用比较广泛;
  3. 将特殊的分隔符作为消息的结束标志,回车换行符就是一种特殊的分隔符;
  4. 通过在消息头中定义长度字段来标识消息的总长度。

  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权威指南学习笔记五——分隔符和定长解码器的应用相关推荐

  1. netty权威指南 学习笔记http

    序 李林峰的<netty权威指南>,从Java的NIO开始介绍,后面介绍TCP粘包拆包.中级篇介绍编解码技术. 第10章介绍了HTTP及netty HTTP+XML的技术. 因为xml实际 ...

  2. netty权威指南学习笔记三——TCP粘包/拆包之粘包现象

    TCP是个流协议,流没有一定界限.TCP底层不了解业务,他会根据TCP缓冲区的实际情况进行包划分,在业务上,一个业务完整的包,可能会被TCP底层拆分为多个包进行发送,也可能多个小包组合成一个大的数据包 ...

  3. netty权威指南学习笔记一——NIO入门(4)AIO

    NIO2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现.异步通道提供以下两种方式获取操作结果. 1.通过java.util.concurrent.Future 类来表示异步操 ...

  4. JavaScript 权威指南-学习笔记(一)

    本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! JavaScript 权威指南-学习笔记 ...

  5. 《Netty权威指南》笔记 —— 第二十、二十一、二十二, 二十三章

    <Netty权威指南>笔记--Netty高级特性 第20章 Netty架构剖析 Reactor通信调度层 职责链 ChannelPipeline 业务逻辑编排层 关键架构质量属性 高性能 ...

  6. Hadoop权威指南学习笔记三

    HDFS简单介绍 声明:本文是本人基于Hadoop权威指南学习的一些个人理解和笔记,仅供学习參考.有什么不到之处还望指出,一起学习一起进步. 转载请注明:http://blog.csdn.net/my ...

  7. Hadoop权威指南学习笔记一

    Hadoop简单介绍 声明:本文是本人基于Hadoop权威指南学习的一些个人理解和笔记,仅供学习參考,有什么不到之处还望指出.一起学习一起进步. 转载请注明:http://blog.csdn.net/ ...

  8. ZeroC Ice权威指南-学习笔记1——hello world

    前言 ZeroC Ice是一款很好的RPC框架,性能极好.但是参考文档不足是其一大问题,这也影响了它的传播.<ZeroC Ice权威指南>是唯一的中文教材,但写的不尽如人意,作为入门教材, ...

  9. Javascript权威指南学习笔记一:数据类型

    决定从最基础的开始学JavaScript,最近看了<<Javascript权威指南>>第3章,记些笔记备忘. 本章一个重点是类型.按我的理解应该如下表所示: 复合类型中,关联数 ...

最新文章

  1. PubChem的Python接口PubChemPy
  2. Android 停止调试程序
  3. python安装教程win8-python 2.7在win8.1上安装的方法
  4. Spring详解:WebServlet 中不能注入Bean对象
  5. linux下oracle修改最大连接数,linux修改TCP最大连接数
  6. 处理移动端pdf展示问题
  7. 【HNOI2017】礼物
  8. java图片色阶调整、亮度调整
  9. xp的guest访问
  10. Jupyter notebook最简原型界面设计 - ipywidgets与lineup_widget
  11. 机刷实名认证软件_代刷网已上架抖音代实名认证和抖音音乐人认证
  12. Paper | Multitask learning
  13. vue-router实现history模式配置
  14. linux操作系统版本_史上最全的Linux 各个发行版本的优点、缺点、发展史介绍
  15. Si9000计算嘉立创JLC04161H-7628(推荐/免费)方法
  16. 我遇见了一个问题求帮助
  17. Parsing error processing resource path jndi:/localhost/JOA/WEB-INF/struts-config
  18. 剑指offer笔记(六)字符串空格替换
  19. Flask 微信公众号开发
  20. 前置知识-辛几何与辛代数、欧式几何与辛几何、Hamilton量

热门文章

  1. hibernate中List一对多映射关系详解
  2. 跟我学Spring3(8.2):对ORM的支持之集成Hibernate3
  3. Struts2 Result详解
  4. 不该被遗忘的nodeName、nodeValue和nodeType!
  5. Struts2中表单与Action传递数据三种方式
  6. golang中的数字签名
  7. 已解决:大家使用原子哥的延时函数delay_ms,delay_us会出现进入延时函数出不来的情况
  8. springmvc十五:数据输出
  9. python六十五:描述符(__get__, __set__, __delete__)
  10. spring boot一:入门