zoukankan      html  css  js  c++  java
  • Netty入门(十)解码分隔符和基于长度的协议

      我们需要区分不同帧的首尾,通常需要在结尾设定特定分隔符或者在首部添加长度字段,分别称为分隔符协议和基于长度的协议,本节讲解 Netty 如何解码这些协议。

    一、分隔符协议

      Netty 附带的解码器可以很容易的提取一些序列分隔:

      

      下面显示了使用 “ ”分隔符的处理:

      

      下面为 LineBaseFrameDecoder 的简单实现:

     1 public class CmdHandlerInitializer extends ChannelInitializer<Channel> {
     2 
     3     @Override
     4     protected void initChannel(Channel ch) throws Exception {
     5         ChannelPipeline pipeline = ch.pipeline();
     6         // 添加解码器,
     7         pipeline.addLast(new CmdDecoder(65 * 1024));
     8         pipeline.addLast(new CmdHandler());
     9     }
    10 
    11     public static final class Cmd {
    12         private final ByteBuf name;    // 名字
    13         private final ByteBuf args;    // 参数
    14         
    15         public Cmd(ByteBuf name, ByteBuf args) {
    16             this.name = name;
    17             this.args = args;
    18         }
    19         
    20         public ByteBuf name() {
    21             return name;
    22         }
    23         
    24         public ByteBuf args() {
    25             return args;
    26         }
    27     }
    28     
    29     /**
    30      * 根据分隔符将消息解码成Cmd对象传给下一个处理器
    31      */
    32     public static final class CmdDecoder extends LineBasedFrameDecoder {
    33 
    34         public CmdDecoder(int maxLength) {
    35             super(maxLength);
    36         }
    37         
    38         @Override
    39         protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
    40             // 通过结束分隔符从 ByteBuf 提取帧
    41             ByteBuf frame = (ByteBuf)super.decode(ctx, buffer);
    42             if(frame == null)
    43                 return null;
    44             int index = frame.indexOf(frame.readerIndex(), frame.writerIndex(), (byte)' ');
    45             // 提取 Cmd 对象
    46             return new Cmd(frame.slice(frame.readerIndex(), index), 
    47                     frame.slice(index+1, frame.writerIndex()));
    48         }
    49     }
    50     
    51     public static final class CmdHandler extends SimpleChannelInboundHandler<Cmd> {
    52 
    53         @Override
    54         protected void channelRead0(ChannelHandlerContext ctx, Cmd msg) throws Exception {
    55             // 处理 Cmd 信息
    56         }
    57         
    58     }
    59 }

       上面的例子主要实现了利用换行符‘ ’分隔帧,然后将每行数据解码成一个 Cmd 实例。

    二、基于长度的协议 

       基于长度的协议在帧头定义了一个帧编码的长度,而不是在结束位置用一个特殊的分隔符来标记。Netty 提供了两种编码器,用于处理这种类型的协议,如下:

      

       FixedLengthFrameDecoder 的操作是提取固定长度每帧 8 字节,如下图所示:

      

      但大部分时候,我们会把帧的大小编码在头部,这种情况可以使用 LengthFieldBaseFrameDecoder,它会提取帧的长度并根据长度读取帧的数据部分,如下:

      

      下面是 LengthFieldBaseFrameDecoder 的一个简单应用:

     1 /**
     2  * 基于长度的协议
     3  * LengthFieldBasedFrameDecoder
     4  */
     5 public class LineBasedHandlerInitializer extends ChannelInitializer<Channel> {
     6 
     7     @Override
     8     protected void initChannel(Channel ch) throws Exception {
     9         ChannelPipeline pipeline = ch.pipeline();
    10         // 用于提取基于帧编码长度8个字节的帧
    11         pipeline.addLast(new LengthFieldBasedFrameDecoder(65*1024, 0, 8));
    12         pipeline.addLast(new FrameHandler());
    13     }
    14     
    15     public static final class FrameHandler extends SimpleChannelInboundHandler<ByteBuf> {
    16 
    17         @Override
    18         protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
    19             // TODO 数据处理
    20         }
    21         
    22     }
    23 
    24 }

       上面的例子主要实现了提取帧首部 8 字节的长度,然后提取数据部分进行处理。

  • 相关阅读:
    有关phpmailer的详细介绍及使用方法
    威盾解密
    PHP正则表达式验证是否含有中文
    php防止重复提交表单
    simplexml 对xml的增删改操作
    Javascript正则表达式完全学习手册
    利用JS做到隐藏div和显示div
    js控制div显示与隐藏
    后台登陆地址
    MVC 自定义路由
  • 原文地址:https://www.cnblogs.com/coderJiebao/p/Netty10.html
Copyright © 2011-2022 走看看