Netty入门(五)ChanneHandler
本节主要讨论了 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 的关系:
- Channel 绑定到 ChannelPipeline
- ChannelPipeline 绑定到包含 ChannelHandler 的 Channel
- ChannelHandler
- 当添加 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));
}
写操作流程如下:
- 事件传递给 ChannelPipeline 的第一个 ChannelHandler
- ChannelHandler 通过关联的 ChannelHandlerContext 传递事件给 ChannelPipeline 中的下一个 ChannelHandler
- 与 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));
流程如下:
- 直接从特定的 ChannelHandler 开始执行
- 事件发送到下一个 ChannelHandler
- 经过最后一个 ChannelHandler 后,事件从 ChannelPipeline 移除
Netty入门(五)ChanneHandler的更多相关文章
- Netty入门
一.NIO Netty框架底层是对NIO的高度封装,所以想要更好的学习Netty之前,应先了解下什么是NIO - NIO是non-blocking的简称,在jdk1.4 里提供的新api,他的他的特性 ...
- Netty入门教程——认识Netty
什么是Netty? Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架. Netty 是一个广泛使用的 Java 网络编程框架(N ...
- Netty入门与实战教程总结分享
前言:都说Netty是Java程序员必须要掌握的一项技能,带着不止要知其然还要知其所以然的目的,在慕课上找了一个学习Netty源码的教程,看了几章后着实有点懵逼.虽然用过Netty,并且在自己的个人网 ...
- openresty 前端开发入门五之Mysql篇
openresty 前端开发入门五之Mysql篇 这章主要演示怎么通过lua连接mysql,并根据用户输入的name从mysql获取数据,并返回给用户 操作mysql主要用到了lua-resty-my ...
- Netty(五)序列化protobuf在netty中的使用
protobuf是google序列化的工具,主要是把数据序列化成二进制的数据来传输用的.它主要优点如下: 1.性能好,效率高: 2.跨语言(java自带的序列化,不能跨语言) protobuf参考文档 ...
- Thinkphp入门 五 —模型 (49)
原文:Thinkphp入门 五 -模型 (49) [数据库操作model模型] model 模型 数据库操作 tp框架主要设计模式:MVC C:controller 控制器 shop/Li ...
- DevExpress XtraReports 入门五 创建交叉表报表
原文:DevExpress XtraReports 入门五 创建交叉表报表 本文只是为了帮助初次接触或是需要DevExpress XtraReports报表的人群使用的,为了帮助更多的人不会像我这样浪 ...
- Netty入门之客户端与服务端通信(二)
Netty入门之客户端与服务端通信(二) 一.简介 在上一篇博文中笔者写了关于Netty入门级的Hello World程序.书接上回,本博文是关于客户端与服务端的通信,感觉也没什么好说的了,直接上代码 ...
- Netty入门之HelloWorld
Netty系列入门之HelloWorld(一) 一. 简介 Netty is a NIO client server framework which enables quick and easy de ...
- 脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?
本文引用了公众号纯洁的微笑作者奎哥的技术文章,感谢原作者的分享. 1.前言 老于网络编程熟手来说,在测试和部署网络通信应用(比如IM聊天.实时音视频等)时,如果发现网络连接超时,第一时间想到的就是 ...
随机推荐
- [日常] Go语言圣经-竞争条件习题
package main import( "fmt" "sync" ) var balance int func Deposit(amount int) { b ...
- Java基础——String类(一)
一.String 类代表字符串 Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现. 字符串是常量:它们的值在创建之后不能更改.字符串缓冲区支持可变的字符串 ...
- 【JavaFx教程】第二部分:Model 和 TableView
第二部分的主题 创建一个 模型 类. 在 ObservableList 使用模型类. 使用 Controllers 在 TableView 上显示数据. 创建 模型 类. 我们需要一个模型类来保存联系 ...
- Code Signal_练习题_chessBoardCellColor
Given two cells on the standard chess board, determine whether they have the same color or not. Exam ...
- Gruntfile.js文件配置项
GRUNT安装与配置 Posted on 2016-08-19 18:13 听风吹来的种子 阅读(47) 评论(0) 编辑 收藏 安装 CLI npm install -g grunt-cli//全局 ...
- 水平方向margin:auto
先上图 由图可看到,块级元素的水平方向上又"7大属性":margin-left.border-left.padding-left.margin-left.width.paddi ...
- element-ui inputNumber、Card 、Breadcrumb组件源码分析整理笔记(三)
inputNumber组件 <template> <!--@dragstart.prevent禁止input中数字的拖动--> <div @dragstart.preve ...
- require.js的基本概念及使用流程(1)
今天,我们来说一说requireJS的基本概念,在下一篇随笔中我们再去讨论讨论requireJS的使用步骤 这一篇都是一些概念性比较强的东西,希望大家擦亮自己的钛合金狗眼好好看看概念,好吧 首先,什么 ...
- MySQL数据库封装和分页查询
1.数据库封装 <?php //我用的数据库名是housedb class DBDA {public $host="localhost";public $uid=" ...
- 网络基础 利用vnc viewer访问在vmware虚拟机上的linux
利用vnc viewer访问在vmware虚拟机上的linux by:授客 QQ:1033553122 Linux服务器为架设在VMware之上的虚拟机,那么可以直接使用VMware自带的vnc,而不 ...