ChannelInitializer在Netty中是一个很重要的东西。也是4.x版本中用户接触比较多的一个类

它本身是继承ChannelInboundHandlerAdapter的。实现ChannelInboundHandler类


【推荐1】Netty4 ChannelPipeLine分析  ★★★★☆

【推荐2】java netty之ChannelPipeline  ★★★☆☆

【推荐3】netty源码分析之FrameDecoder(LengthFieldBasedFrameDecoder)  ★★★☆☆

ChannelPipeline 中的中的事件流程

  • I/O Request
    via Channel or
    ChannelHandlerContext
    |
    +---------------------------------------------------+---------------+
    | ChannelPipeline | |
    | \|/ |
    | +---------------------+ +-----------+----------+ |
    | | Inbound Handler N | | Outbound Handler 1 | |
    | +----------+----------+ +-----------+----------+ |
    | /|\ | |
    | | \|/ |
    | +----------+----------+ +-----------+----------+ |
    | | Inbound Handler N-1 | | Outbound Handler 2 | |
    | +----------+----------+ +-----------+----------+ |
    | /|\ . |
    | . . |
    | ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
    | [ method call] [method call] |
    | . . |
    | . \|/ |
    | +----------+----------+ +-----------+----------+ |
    | | Inbound Handler 2 | | Outbound Handler M-1 | |
    | +----------+----------+ +-----------+----------+ |
    | /|\ | |
    | | \|/ |
    | +----------+----------+ +-----------+----------+ |
    | | Inbound Handler 1 | | Outbound Handler M | |
    | +----------+----------+ +-----------+----------+ |
    | /|\ | |
    +---------------+-----------------------------------+---------------+
    | \|/
    +---------------+-----------------------------------+---------------+
    | | | |
    | [ Socket.read() ] [ Socket.write() ] |
    | |
    | Netty Internal I/O Threads (Transport Implementation) |
    +-------------------------------------------------------------------+

    这个图是joc里面的ChannelPipeline文档里面的一张示意图。图示的内容是。
    当有IO请求
    ChannelInboundHandler 是从上之下搜索,相应的实现。一次执行。
    4.x版本中的Netty。启用了一个新的东西用于初始ChannelPipeline -> ChannelInitializer<Channel>
    ChannelInitializer有一个抽象未实现的方法:initChannel(C ch) 用于开发者自己定义相关的Handler添加到信道中。原理及详细分析请参考上面推荐的两篇文章。可能版本还不是最新的。但是4.x版本之后的一些大致的思路都是没有什么变化。
    
    下面把自己写的小东西贴出来。
    
     package com.engine.netty.server.initializer;
    
     import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
    import io.netty.handler.codec.LengthFieldPrepender;
    import io.netty.handler.timeout.IdleStateHandler; import com.engine.netty.server.handler.IdleStateCheckHandler;
    import com.engine.netty.server.handler.codec.DecoderAMF3;
    import com.engine.netty.server.handler.codec.EncoderAMF3;
    import com.engine.netty.socket.ChatServerHandler; /**
    * Creates a newly configured {@link ChannelPipeline} for a new channel.
    */
    public class NettyServerInitializer extends ChannelInitializer<SocketChannel> { @Override
    public void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline(); // 编码或者解码 拆包
    /*
    * 需要和客户端订立 相关通信协议底层规则 - 【消息长度(2 : short表示 2个字节)】【消息内容】
    * lengthFieldLength => 是整数 - 占四个字节 所以同时偏移四个字节 => (0, 4, 0, 4)
    *
    * */
    pipeline.addLast("framer", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
    pipeline.addLast("prepender", new LengthFieldPrepender(4, false)); // 空闲状态检查 间隔无消息,断开连接
    pipeline.addLast("idleStateCheck", new IdleStateHandler(0, 0, 600));
    pipeline.addLast("idleCheckHandler", new IdleStateCheckHandler()); // AMF3 编码或者解码
    pipeline.addLast("decoder", new DecoderAMF3());
    pipeline.addLast("encoder", new EncoderAMF3()); // 序列化对象object编码和解码 【用于Java Object】
    //pipeline.addLast("objectEncoder", new ObjectEncoder());
    //pipeline.addLast("objectDecoder", new ObjectDecoder(ClassResolvers.cacheDisabled(null))); /*// 以UTF-8格式编码和解码 数据 【用于字符串】
    pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
    pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));*/ // and then business logic.
    pipeline.addLast("handler", new ChatServerHandler());
    }
    }

    NettyServerInitializer

    发出去AMF3的东西是上一篇记录里面写的之外。其他两种编码和解码都是官网有相对应例子的。编码和解码说白其实就是对字节数据的翻译。在Netty中数据已ByteBuf保存。ByteBuf提供了很多的方法读取相对应的数据。在这里就不详细介绍了。有兴趣的可以去看看官网的示例。或者是API 文档。文档中有一些类。官方都提供了相对应的代码范例。
    【空闲状态检查】是官网API文档中找到的。
    io.netty.handler.timeout 这个包中就是Netty提供的一些关于读超时,写超时,读写超时。空闲时间等的东西。 LengthFieldBasedFrameDecoder 和 LengthFieldPrepender
    这两个编码解码 相当于是对数据的处理。
    先讲一下
    LengthFieldBasedFrameDecoder :
    直接通过命名大家很明显的可以理解这个类 一个根据帧长度的解码类。到底是怎么样子的呢?其实很简单。 LengthFieldBasedFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip)
    参数:
    maxFrameLength: the maximum length of the frame. If the length of the frame is greater than this value, TooLongFrameException will be thrown. (最大帧长)
    lengthFieldOffset: the offset of the length field (偏移量)
    lengthFieldLength: the length of the length field
    lengthAdjustment: the compensation value to add to the value of the length field
    initialBytesToStrip: the number of first bytes to strip out from the decoded frame
    它有5个参数 (详细的解释可以参考推荐文章3).
    说简单点就是第一个是字节消息的最大长度。第二个参数是消息长度这个字节的偏移量。第三个参数是描述字节消息长度的那部分的长度。第四个不解释。第五个是跳过首部的字节长度
    我这边写的0202其实意思就是 我的消息长度是有一个short类型来描述的。short类型的数据占2个字节。第二个2是说在返回最终解码的数据的时候跳过这个描述长度的字节数。
    API文档中的:
    2 bytes length field at offset 0, strip header :
    Because we can get the length
    of the content by calling ByteBuf.readableBytes(), you might want to strip the
    length field by specifying initialBytesToStrip. In this example, we specified 2,
    that is same with the length of the length field, to strip the first two bytes.

    lengthFieldOffset = 0
    lengthFieldLength = 2
    lengthAdjustment = 0

    initialBytesToStrip = 2 (= the length of the Length field) BEFORE
    DECODE (14 bytes) AFTER DECODE (12 bytes)
    +--------+----------------+ +----------------+
    | Length | Actual Content |----->| Actual Content |
    | 0x000C | "HELLO, WORLD" | | "HELLO, WORLD" |
    +--------+----------------+ +----------------+  最后的ChatServerHandler是我自己写的逻辑的Handler
    
    
    貌似就写到这边了。O(∩_∩)O哈哈~
    
    

【Netty学习】 ChannelInitializer 学习的更多相关文章

  1. 【Netty源码学习】ServerBootStrap

    上一篇博客[Netty源码学习]BootStrap中我们介绍了客户端使用的启动服务,接下来我们介绍一下服务端使用的启动服务. 总体来说ServerBootStrap有两个主要功能: (1)调用父类Ab ...

  2. Netty 源码学习——客户端流程分析

    Netty 源码学习--客户端流程分析 友情提醒: 需要观看者具备一些 NIO 的知识,否则看起来有的地方可能会不明白. 使用版本依赖 <dependency> <groupId&g ...

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

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

  4. netty权威指南学习笔记五——分隔符和定长解码器的应用

    TCP以流的方式进行数据传输,上层应用协议为了对消息进行区分,通常采用以下4中方式: 消息长度固定,累计读取到长度综合为定长LEN的报文后,就认为读取到了一个完整的消息,将计数器置位,重新开始读取下一 ...

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

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

  6. Netty源码学习系列之4-ServerBootstrap的bind方法

    前言 今天研究ServerBootstrap的bind方法,该方法可以说是netty的重中之重.核心中的核心.前两节的NioEventLoopGroup和ServerBootstrap的初始化就是为b ...

  7. 【Netty源码学习】DefaultChannelPipeline(三)

    上一篇博客中[Netty源码学习]ChannelPipeline(二)我们介绍了接口ChannelPipeline的提供的方法,接下来我们分析一下其实现类DefaultChannelPipeline具 ...

  8. 【Netty源码学习】ChannelPipeline(一)

    ChannelPipeline类似于一个管道,管道中存放的是一系列对读取数据进行业务操作的ChannelHandler. 1.ChannelPipeline的结构图: 在之前的博客[Netty源码学习 ...

  9. Netty 源码学习——EventLoop

    Netty 源码学习--EventLoop 在前面 Netty 源码学习--客户端流程分析中我们已经知道了一个 EventLoop 大概的流程,这一章我们来详细的看一看. NioEventLoopGr ...

随机推荐

  1. POJ 1062 dij

    一道读题读的不明所以的题... 每个人只能接受和自己等级差距不超过m的人进行交易 包括间接交易 所以我们可以枚举每一个长度为m的围绕着酋长的等级区间 每次都对这个等级区间内的人进行操作 求dis[1] ...

  2. CodeForces 621C 数学概率期望计算

    昨天训练赛的题..比划了好久才想出来什么意思 之前想的是暴力for循环求出来然后储存数组 后来又想了想 自己萌的可以.. 思路就是求出来每个人与他的右边的人在一起能拿钱的概率(V(或)的关系)然后*2 ...

  3. DWZ的选择带回功能无法带回第一个value中的值

    <volist name="node1._child" id="node2"> 这里的value中第一个id是无法带回给上一个页面的..如果要带回则 ...

  4. treeview子节点文本过长超过DIV自动换行CSS解决

    //文本不换行 .ygtvcell.ygtvcontent{ white-space: nowrap; } //文本超过div出现滚动条 .main .buttom .right{ overflow- ...

  5. SHELL 中的重定向和管道

    1. 什么叫重定向将输入或输出重新指定到别的位置. 2. 重定向输出2.1.命令执行数据流文件/设备---- 标准输入 -->命令 --- 标准输出 -->文件/设备            ...

  6. shell的if else 以及大于,小于等逻辑表达式

    if ....; then .... elif ....; then .... else .... fi 大多数情况下,可以使用测试命令来对条件进行测试.比如可以比较字符串.判断文件是否存在及是否可读 ...

  7. a read only variable

    SHOW VARIABLES LIKE '%FORMAT%' SET DATE_FORMAT ='%Y-%m-%d' [SQL]SET DATE_FORMAT ='%Y-%m-%d' [Err] 12 ...

  8. C、VDD、VSS、 VEE 和VPP的区别

    http://www.cnblogs.com/crazybingo/archive/2010/05/14/1735802.html C.VDD.VSS. VEE 和VPP的区别 在电子电路中,常可以看 ...

  9. nRF51822之WDT浅析

    看门狗定时器 NRF51822 的看门狗定时器是倒计数器, 当计数值减少到 0 时产生 TIMEOUT 事件. 通过 START task 来启动看门狗定时器. 看门狗定时器启动时,如没有其他 32. ...

  10. nrf51822裸机教程-硬件timer

    该讲介绍51822的Timer/Counter模块工作在timer模式下(定时器模式,还可以工作为计数器模式) 如何操作 51822的Timer/Counter结构如下图所示 Timer模块从PCLK ...