本节主要讨论了 Netty 的数据处理组件 ChannelHandler。

一、Channel 生命周期

  Channel 有个简单但强大的状态模型,下面是 Channel 的四个状态:

  

  Channel 的正常生命周期如下图,当这些状态发生变化时,对应的事件将会生成。

  

二、ChannelHandler 生命周期

  ChannelHandler 定义的生命周期如下,当 ChannelHandler 添加到 ChannelPipeline,或者从 ChannelPipeline 移除后,这些将会调用。

  

三、ChannelInbounderHandler

  ChannelInboundHandler 的生命周期方法如下,当接收到数据或者与之关联的 Channel 状态改变时调用。

  

  可以看到,这些方法与 Channel 的生命周期接近。

  其中 channelRead 和 channelReadComplete 方法在读操作开始和完成时调用。

  另外,channelWritabilityChanged 方法在 channel 写状态发生变化时调用。

四、ChannelOutboundHandler

  ChannelOutboundHandler 提供了出站操作时调用的方法。

  另外,它具有在请求时演示操作或者事件的能力。比如,当你在写数据到远程的过程中被意外暂停,你可以延时进行刷新操作,然后在迟些时候继续。

  下面是提供的方法(继承自 ChannelHandler 未列出来):

  

五、资源管理

  Netty 使用引用计数器来处理池化的 ByteBuf。所以当 ByteBuf 完全处理后,要确保引用计数器被调整。

  当你覆盖了 channelRead 操作,在处理完消息之后,需要释放它,如下:

 public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
/**
* 收到数据时调用
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 丢弃收到的数据
((ByteBuf) msg).release();
}
}

  Netty 提供了一个特殊的称为 SimpleChannelInboundHander 的实现,该实现将在用户通过 channelRead0() 方法处理完数据之后,自动释放该消息。

  当你在处理写操作,并丢弃消息时,你需要通知 ChannelPromise 数据已经被处理,如下:

 public class DiscardOutbounderHandler extends ChannelOutboundHandlerAdapter {
@Override
public void write(ChannelHandlerContext ctx,
Object msg, ChannelPromise promise) throws Exception {
ReferenceCountUtil.release(msg); // 释放资源
promise.setSuccess(); // 通知 ChannelPromise 数据已经被处理
}
}

六、使用 ChannelHandler

  下图展示了 ChannelPipeline,Channel,ChannelHandler 和 ChanelHandlerContext 的关系:

  

  1. Channel 绑定到 ChannelPipeline
  2. ChannelPipeline 绑定到包含 ChannelHandler 的 Channel
  3. ChannelHandler
  4. 当添加 ChannelHandler 到 ChannelPipeline 时,ChannelHandlerContext 被创建

  如果要完成一个写操作,有以下两种方式:

  第一种就是从 ChannelHandlerContext 获取到 Channel 的引用,执行 Channel 上的 write() 方法,如下:

 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 丢弃收到的数据
((ByteBuf) msg).release(); Channel channel = ctx.channel(); // 获取channel引用
// 通过channel写缓存
channel.write(Unpooled.copiedBuffer("Netty", CharsetUtil.UTF_8));
}

  第二种是从 ChannelHandlerContext 获取到 ChannelPipeline 的引用,执行 ChannelPipeline 上的 write() 方法,如下:

 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ChannelPipeline pipeline = ctx.pipeline(); // 获取pipeline引用
// 通过pipeline写缓存
pipeline.write(Unpooled.copiedBuffer("Netty", CharsetUtil.UTF_8));
}

  写操作流程如下:

  

  1. 事件传递给 ChannelPipeline 的第一个 ChannelHandler
  2. ChannelHandler 通过关联的 ChannelHandlerContext 传递事件给 ChannelPipeline 中的下一个 ChannelHandler
  3. 与 2 类似

  但是有些时候不希望总是从 ChannelPipeline 的第一个 ChannelHandler 开始事件,我们希望从一个特定的 ChannelHandler 开始处理。你必须引用于此 ChannelHandler 的前一个 ChannelHandler 关联的 ChannelHandlerContext,利用它调用与自身关联的 ChannelHandler 的下一个 ChannelHandler。如下:

 ChannelHandlerContext ctx = context;   // 获得 ChannelHandlerContext引用
// write()将会把缓冲区发送到下一个ChannelHandler
ctx.write(Unpooled.copiedBuffer("Netty in Action", CharsetUtil.UTF_8));

  流程如下:

  

  1. 直接从特定的 ChannelHandler 开始执行
  2. 事件发送到下一个 ChannelHandler
  3. 经过最后一个 ChannelHandler 后,事件从 ChannelPipeline 移除

Netty入门(五)ChanneHandler的更多相关文章

  1. Netty入门

    一.NIO Netty框架底层是对NIO的高度封装,所以想要更好的学习Netty之前,应先了解下什么是NIO - NIO是non-blocking的简称,在jdk1.4 里提供的新api,他的他的特性 ...

  2. Netty入门教程——认识Netty

    什么是Netty? Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架. Netty 是一个广泛使用的 Java 网络编程框架(N ...

  3. Netty入门与实战教程总结分享

    前言:都说Netty是Java程序员必须要掌握的一项技能,带着不止要知其然还要知其所以然的目的,在慕课上找了一个学习Netty源码的教程,看了几章后着实有点懵逼.虽然用过Netty,并且在自己的个人网 ...

  4. openresty 前端开发入门五之Mysql篇

    openresty 前端开发入门五之Mysql篇 这章主要演示怎么通过lua连接mysql,并根据用户输入的name从mysql获取数据,并返回给用户 操作mysql主要用到了lua-resty-my ...

  5. Netty(五)序列化protobuf在netty中的使用

    protobuf是google序列化的工具,主要是把数据序列化成二进制的数据来传输用的.它主要优点如下: 1.性能好,效率高: 2.跨语言(java自带的序列化,不能跨语言) protobuf参考文档 ...

  6. Thinkphp入门 五 —模型 (49)

    原文:Thinkphp入门 五 -模型 (49) [数据库操作model模型] model  模型  数据库操作 tp框架主要设计模式:MVC C:controller   控制器   shop/Li ...

  7. DevExpress XtraReports 入门五 创建交叉表报表

    原文:DevExpress XtraReports 入门五 创建交叉表报表 本文只是为了帮助初次接触或是需要DevExpress XtraReports报表的人群使用的,为了帮助更多的人不会像我这样浪 ...

  8. Netty入门之客户端与服务端通信(二)

    Netty入门之客户端与服务端通信(二) 一.简介 在上一篇博文中笔者写了关于Netty入门级的Hello World程序.书接上回,本博文是关于客户端与服务端的通信,感觉也没什么好说的了,直接上代码 ...

  9. Netty入门之HelloWorld

    Netty系列入门之HelloWorld(一) 一. 简介 Netty is a NIO client server framework which enables quick and easy de ...

  10. 脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?

    本文引用了公众号纯洁的微笑作者奎哥的技术文章,感谢原作者的分享. 1.前言   老于网络编程熟手来说,在测试和部署网络通信应用(比如IM聊天.实时音视频等)时,如果发现网络连接超时,第一时间想到的就是 ...

随机推荐

  1. [日常] Go语言圣经-竞争条件习题

    package main import( "fmt" "sync" ) var balance int func Deposit(amount int) { b ...

  2. Java基础——String类(一)

    一.String 类代表字符串 Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现. 字符串是常量:它们的值在创建之后不能更改.字符串缓冲区支持可变的字符串 ...

  3. 【JavaFx教程】第二部分:Model 和 TableView

    第二部分的主题 创建一个 模型 类. 在 ObservableList 使用模型类. 使用 Controllers 在 TableView 上显示数据. 创建 模型 类. 我们需要一个模型类来保存联系 ...

  4. Code Signal_练习题_chessBoardCellColor

    Given two cells on the standard chess board, determine whether they have the same color or not. Exam ...

  5. Gruntfile.js文件配置项

    GRUNT安装与配置 Posted on 2016-08-19 18:13 听风吹来的种子 阅读(47) 评论(0) 编辑 收藏 安装 CLI npm install -g grunt-cli//全局 ...

  6. 水平方向margin:auto

    先上图   由图可看到,块级元素的水平方向上又"7大属性":margin-left.border-left.padding-left.margin-left.width.paddi ...

  7. element-ui inputNumber、Card 、Breadcrumb组件源码分析整理笔记(三)

    inputNumber组件 <template> <!--@dragstart.prevent禁止input中数字的拖动--> <div @dragstart.preve ...

  8. require.js的基本概念及使用流程(1)

    今天,我们来说一说requireJS的基本概念,在下一篇随笔中我们再去讨论讨论requireJS的使用步骤 这一篇都是一些概念性比较强的东西,希望大家擦亮自己的钛合金狗眼好好看看概念,好吧 首先,什么 ...

  9. MySQL数据库封装和分页查询

    1.数据库封装 <?php //我用的数据库名是housedb class DBDA {public $host="localhost";public $uid=" ...

  10. 网络基础 利用vnc viewer访问在vmware虚拟机上的linux

    利用vnc viewer访问在vmware虚拟机上的linux by:授客 QQ:1033553122 Linux服务器为架设在VMware之上的虚拟机,那么可以直接使用VMware自带的vnc,而不 ...