Netty事件监听和处理(下)
上一篇 介绍了事件监听、责任链模型、socket接口和IO模型、线程模型等基本概念,以及Netty的整体结构,这篇就来说下Netty三大核心模块之一:事件监听和处理。
前面提到,Netty是一个NIO框架,它将IO通道的建立、可读、可写等状态变化,抽象成事件,以责任链的方式进行传递,可以在处理链上插入自定义的Handler,对感兴趣的事件进行监听和处理。
通过介绍,你会了解到:
- 事件监听和处理模型
- 事件监听:EventLoop
- 事件处理:ChannelPipeline和ChannelHandler
- 使用Netty实现Websocket协议
文章末尾有福利 ~
事件监听和处理模型
进行网络编程时,一般的编写过程是这样的:
- 创建服务端Socket,监听某个端口;
- 当有客户端连接时,会创建一个新的客户端Socket,监听数据的可读、可写状态,每一个连接请求都会创建一个客户端Socket;
- 读取和写入数据都会调用Socket提供的接口,接口列表在上一篇提到过;
传统的模型,每个客户端Socket会创建一个单独的线程监听socket事件,一方面系统可创建的线程数有限,限制了并发数,一方面线程过多,线程切换频繁,导致性能严重下降。
随着操作系统IO模型的发展,可以采用多路复用IO,一个线程监听多个Socket,另外,服务端处理客户端连接,与客户端Socket的监听,可以在不同的线程进行处理。
Netty就是采用多路复用IO进行事件监听,另外,使用不同的线程分别处理客户端的连接、数据读写。
整个处理结构如下图,简单说明下:
- Boss EventLoopGroup主要处理客户端的connect事件,包含多个EventLoop,每个EventLoop一个线程;
- Worker EventLoopGroup主要处理客户端Socket的数据read、write事件,包含多个EventLoop,每个EventLoop一个线程;
- 无论是Boos还是Worker,事件的处理都是通过Channel Pipleline组织的,它是责任链模式的实现,包含一个或多个Handler;
- 侦听一个端口,只会绑定到Boss EventLoopGroup中的一个Eventloop;
- Worker EventLoopGroup中的一个Eventloop,可以监听多个客户端Socket;

EventLoop
一个EventLoop其实和一个特定的线程绑定, 并且在其生命周期内, 绑定的线程都不会再改。
EventLoop肩负着两种任务:
- 第一个是作为 IO 线程, 执行与 Channel 相关的 IO 操作, 包括 调用select等待就绪的IO事件、读写数据与数据的处理等;
- 第二个任务是作为任务队列, 执行 taskQueue 中的任务, 例如用户调用eventLoop.schedule提交的定时任务也是这个线程执行的;
第一个任务比较好理解,主要解释下第二个:从socket数据到数据处理,再到写入响应数据,Netty都在一个线程中处理,主要是为了线程安全考虑,减少竞争和线程切换,通过任务队列的方式,可以在用户线程提交处理逻辑,在Eventloop中执行。
整个EventLoop干的事情就是select -> processIO -> runAllTask,processIO处理IO事件相关的逻辑,runAllTask处理任务队列中的任务,如果执行的任务过多,会影响IO事件的处理,所以会限制任务处理的时间,整个处理过程如下图:

EventLoop的run代码如下:
1 |
protected void run() {
|
ChannelPipeline和ChannelHandler
ChannelPipeline是一个接口,其有一个默认的实现类DefaultChannelPipeline,内部有两个属性:head和tail,
这两者都实现了ChannelHandler接口,对应处理链的头和尾。
1 |
protected DefaultChannelPipeline(Channel channel) {
|
每个Channel创建时,会创建一个ChannelPipeline对象,来处理channel的各种事件,可以在运行时动态进行动态修改其中的 ChannelHandler。
ChannelHandler承载业务处理逻辑的地方,我们接触最多的类,可以自定义Handler,加入处理链中,实现自定义逻辑。
ChannelHandler 可分为两大类:ChannelInboundHandler 和 ChannelOutboundHandle,这两接口分别对应入站和出站消息的处理,对应数据读取和数据写入。它提供了接口方法供我们实现,处理各种事件。
1 |
public interface ChannelInboundHandler extends ChannelHandler {
|
自定义Handler时,一般继承ChannelInboundHandlerAdapter或 ChannelOutboundHandlerAdapter。
需要注意的是,不建议在 ChannelHandler 中直接实现耗时或阻塞的操作,因为这可能会阻塞 Netty 工作线程,导致 Netty 无法及时响应 IO 处理。

使用Netty实现Websocket协议
Websocket协议
不是本篇的重点,简单说明下:
- 是一种长连接协议,大部分浏览器都支持,通过websocket,服务端可以主动发消息给客户端;
- Websocket协议,在握手阶段使用HTTP协议,握手完成之后,走Websocket自己的协议;
- Websocket是一种二进制协议;
初始化
Netty提供了ChannelInitializer类方便我们初始化,创建WebSocketServerInitializer类,继承ChannelInitializer类,用于添加ChannelHandler:
1 |
public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> {
@Resource
|
分析下这几个Handler,都是Netty默认提供的:
- HttpServerCodec:用于解析Http请求,主要在握手阶段进行处理;
- HttpObjectAggregator:用于合并Http请求头和请求体,主要在握手阶段进行处理;
- WebSocketServerProtocolHandler:处理Websocket协议;
- CustomTextFrameHandler:自定义的Handler,用于添加自己的业务逻辑。
是不是很方便,经过WebSocketServerProtocolHandler处理后,读取出来的就是文本数据了,不用自己处理数据合包、拆包问题。
CustomTextFrameHandler
自定义的Handler,进行业务处理:
1 |
public class CustomTextFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
|
福利说明
最后,说下福利:小爱音箱F码。
准备了2份,主要为了感谢「微信公众号」和「掘金社区」的朋友,每一份包括1个小爱音箱F码和1个小爱音箱 mini F码。
小米手机F码源自于英文单词”Friend”,是小米公司提供给小米核心用户及为小米做出贡献的网友的优先购买权,如果您有小米F码的话无需等待即可直接利用小米F码购买相关产品!
简单来说,F码就是不用抢了,可以直接购买 ~
抽奖截止时间
4月9号中午12点
抽奖规则
掘金社区
需要关注我的掘金账号才有效,个人主页;
使用微信抽奖助手随机抽取for掘金社区;
微信公众号
需要关注我的微信公众号才有效;
使用微信抽奖助手随机抽取for微信公众号;
Netty事件监听和处理(下)的更多相关文章
- Netty事件监听和处理(上)
陪产假结束了,今天又开始正常上班了,正好赶上米粉节活动,又要忙上一阵了,米粉节活动时间为4.03 - 4.10,有不少优惠,感兴趣的可以关注mi.com或小米商城app. 今天给大家送了福利:小爱音箱 ...
- js中如何在不影响既有事件监听的前提下新增监听器
一. 需求澄清 比如某个按钮已经绑定了2-3个对Window对象的load事件的监听,现在需要添加一个新的对click事件的监听器,但在一定条件下才会同时触发原有的2-3个load监听器,否则只触发新 ...
- 9、JcomboBox下拉框事件监听
9.JcomboBox下拉框事件监听 JComboBox()的事件监听类ItemListener.其范例代码如下: import java.awt.*; import java.awt.event.* ...
- Zookeeper Curator 事件监听 - 秒懂
目录 写在前面 1.1. Curator 事件监听 1.1.1. Watcher 标准的事件处理器 1.1.2. NodeCache 节点缓存的监听 1.1.3. PathChildrenCache ...
- Node.js 教程 05 - EventEmitter(事件监听/发射器 )
目录: 前言 Node.js事件驱动介绍 Node.js事件 注册并发射自定义Node.js事件 EventEmitter介绍 EventEmitter常用的API error事件 继承EventEm ...
- .NET事件监听机制的局限与扩展
.NET中把“事件”看作一个基本的编程概念,并提供了非常优美的语法支持,对比如下C#和Java代码可以看出两种语言设计思想之间的差异. // C#someButton.Click += OnSomeB ...
- 让 select 的 option 标签支持事件监听(如复制操作)
这标题,让option支持事件监听,应该不难的呀,有什么好讲的? 其实还是有的,默认在浏览器代码是无法直接对option标签进行操作的,不仅包括JS事件监听,还是CSS样式设置 查了一些资料,姑且认为 ...
- [JS]笔记12之事件机制--事件冒泡和捕获--事件监听--阻止事件传播
-->事件冒泡和捕获-->事件监听-->阻止事件传播 一.事件冒泡和捕获 1.概念:当给子元素和父元素定义了相同的事件,比如都定义了onclick事件,点击子元素时,父元素的oncl ...
- [No00006A]Js的addEventListener()及attachEvent()区别分析【js中的事件监听】
1.添加时间监听: Chrom中: addEventListener的使用方式: target.addEventListener(type, listener, useCapture); target ...
随机推荐
- 灵感&小思路
1.被处理的数据量级比较大.没有明显规律可循,可以分割.或者提取文件,采用分步和保存思想去解决. 比如在使用python的正则re模块时候,根据被处理对象提取属性抽象一个基类,方法实现分步,并且把中间 ...
- jq事件
1,ready:当DOM载入就绪可以查询及操纵时绑定一个要执行的函数,在使用之前必须确保body元素的onload事件,,没有注册函数,否则不会触发ready函数. $(document).ready ...
- 使用axios向后端传递数据,后端接收不到?
开始使用axios的时候,按照官网的例子请求后端接口,遇到了后端接收不到数据的情况. 翻看了文档也没找到解决方法.先来了解下基本的axios 想要使用axios,需要先安装 npm install a ...
- Cesium home键定位的位置
Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(80, 22, 130, 50);//home定位到中国范围
- 安装Accumulo——突破自己,就是成长
前言 在我刚开始接触分布式集群的时候,是自己在几台虚拟机中手动安装的 Hadoop 和 Spark ,所以当时对 Hadoop 的配置有个简单的印象 ,但是后面发现了 Cloudera 和 Ambar ...
- python趣味 ——奇葩的全局形参
在c++,c#,js等语言中: 函数定义(参数) 函数体:参数修改 这里的参数修改都是仅限于这个函数体内的 python不知道是不是bug,我们这样写: def test(a=[]): a.appen ...
- NGUI_slider
十一.进度条UISlider 1.一般按以下规律使用进度条; 如果某一钟值,他有最大值,需要表达当前的值得占比,则可以使用不可拖动的进度条 如果某一值,他有最大值,需要玩家记性滑动设置,则可以使用可拖 ...
- [译]Android view 测量布局和绘制的流程
原文链接 创造优秀的用户体验是我们开发者的主要目标之一.为此, 我们首先要了解系统是如何工作的, 这样我们才可以更好的与系统配合, 从它的优点中获益, 规避它的缺陷. 之前关于Android渲染过程的 ...
- vs调试正确显示utf8格式字符串
自从将visual studio从2010升级到2015后,发现调用接口的utf8格式字符串不能正常显示了,常常被莫名其妙截断,查了下,原来可以直接将变量拖到watch窗口中,在变量名后面手动添加,s ...
- 笔记:Spring Cloud Ribbon 客户端配置详解
自动化配置 由于 Ribbon 中定义的每一个接口都有多种不同的策略实现,同时这些接口之间又有一定的依赖关系,Spring Cloud Ribbon 中的自动化配置能够很方便的自动化构建接口的具体实现 ...