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字符定长的数据显示。

netty权威指南学习笔记五——分隔符和定长解码器的应用的更多相关文章

  1. netty权威指南学习笔记六——编解码技术之MessagePack

    编解码技术主要应用在网络传输中,将对象比如BOJO进行编解码以利于网络中进行传输.平常我们也会将编解码说成是序列化/反序列化 定义:当进行远程跨进程服务调用时,需要把被传输的java对象编码为字节数组 ...

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

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

  3. netty权威指南学习笔记二——netty入门应用

    经过了前面的NIO基础知识准备,我们已经对NIO有了较大了解,现在就进入netty的实际应用中来看看吧.重点体会整个过程. 按照权威指南写程序的过程中,发现一些问题:当我们在定义handler继承Ch ...

  4. netty权威指南学习笔记八——编解码技术之JBoss Marshalling

    JBoss Marshalling 是一个java序列化包,对JDK默认的序列化框架进行了优化,但又保持跟java.io.Serializable接口的兼容,同时增加了一些可调参数和附加特性,这些参数 ...

  5. netty权威指南学习笔记一——NIO入门(1)BIO

    公司的一些项目采用了netty框架,为了加速适应公司开发,本博主认真学习netty框架,前一段时间主要看了看书,发现编程这东西,不上手还是觉得差点什么,于是为了加深理解,深入学习,本博主还是决定多动手 ...

  6. netty权威指南学习笔记七——编解码技术之GoogleProtobuf

    首先我们来看一下protobuf的优点: 谷歌长期使用成熟度高: 跨语言支持多种语言如:C++,java,Python: 编码后消息更小,更利于存储传输: 编解码性能高: 支持不同协议版本的兼容性: ...

  7. netty权威指南学习笔记四——TCP粘包/拆包之粘包问题解决

    发生了粘包,我们需要将其清晰的进行拆包处理,这里采用LineBasedFrameDecoder来解决 LineBasedFrameDecoder的工作原理是它依次遍历ByteBuf中的可读字节,判断看 ...

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

    经过前面的铺垫,在这一节我们进入NIO编程,NIO弥补了原来同步阻塞IO的不足,他提供了高速的.面向块的I/O,NIO中加入的Buffer缓冲区,体现了与原I/O的一个重要区别.在面向流的I/O中,可 ...

  9. IDA Pro 权威指南学习笔记(五) - IDA 主要的数据显示窗口

    在默认配置下,IDA(从 6.1 版开始)会在对新二进制文件的初始加载和分析阶段创建 7 个显示窗口 3 个立即可见的窗口分别为 IDA-View 窗口.函数窗口和消息输出窗口 可以通过 View - ...

随机推荐

  1. 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 ...

  2. 移动端300毫秒事件响应延迟解决方法[fastclick]

    vue-cli[2.x]中: 安装 npm install fastclick --save 使用: 在main.js中 :先 import fastClick from 'fastclick' 然后 ...

  3. AtCoder agc007_d Shik and Game

    洛谷题目页面传送门 & AtCoder题目页面传送门 有\(1\)根数轴,Shik初始在位置\(0\).数轴上有\(n\)只小熊,第\(i\)只在位置\(a_i\).Shik每秒可以向左移动\ ...

  4. Node.js之EventEmiter

    参考: 1. Node.js之EventEmiter讲解 2. Node.js之events事件 3. 在线运行node.js代码 Node.js主要API使用异步事件驱动模型,异步I/O操作完成时, ...

  5. 运行cmd直接进入指定目录下的命令

    新建一个.bat批处理文件,文件命令为@ECHO OFF cmd /k cd /d c:data 运行该批处理文件cmd就可进入指定的文件夹,感兴趣的朋友可以参考下啊 新建一个.bat批处理文件,文件 ...

  6. 三 HTML框架标签

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. 入门学习C链接

    参考链接:http://c.biancheng.net/view/465.html 在里面链接下载了:code:block,还有C语言入门的PDF文件. 常看网站:https://www.cnblog ...

  8. java并发队列

    阻塞队列 常见的阻塞队列有ArrayBlockingQueue,LinkedBlockingDeque,LinkedBlockingQueue,这些队列有界且可以阻塞线程 ArrayBlockingQ ...

  9. Linux和云供应商Red Hat被IBM以34亿美元的价格收购

    导读 今天的主题包括IBM以340亿美元收购Red Hat,人性化是使人工智能成功的关键.两家公司于10月28日宣布,IBM正以340亿美元的价格收购Linux和云技术供应商Red Hat,以期改变云 ...

  10. 第2节 storm路由器项目开发:1 - 7、网络路由器项目

    网安需求: 1:IFTTT:随着物联网的兴起,if this then that .如果出现这种情况,那么及时反映做出对应的操作. 判断手机号黑白名单,mac地址黑白名单.如果是碰到手机号或者mac地 ...