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 ...
随机推荐
- mysql初步学习
1.insert_select 的使用:从一个表复制数据给另一个表 INSERT INTO students(name,sex,LikeBooksNUM,LikesportNUM,average) S ...
- java web需要好好掌握的一些东西
这是一些需要好好的复习的东西 本来存了个文档 怕整丢了 就在这里保存一下 java 基础 重点关注集合 如list hashmap等使用(有时间多看看hashmap的实现原理 问的比较多)多线程 ...
- windows7下django项目搭建
参考视频教程 http://study.163.com/course/ http://www.bilibili.com/video/av8915600/ http://www.bilibil ...
- Java 小记 — Spring Boot 注解
前言 本篇随笔将对 Spring Boot 中的常用注解做一个简单的整理归档,写作顺序将从启动类开始并逐步向内外扩展,目的即为了分享也为了方便自己日后的回顾与查阅. 1. Application 启动 ...
- PHP开发中涉及到emoji表情的几种处理方法
最近几个月做微信开发比较多,存储微信昵称必不可少 可这万恶的微信支持emoji表情做昵称,这就有点蛋疼了 一般Mysql表设计时,都是用UTF8字符集的.把带有emoji的昵称字段往里面insert一 ...
- 堆排序(Java数组实现)
堆排序:利用大根堆 数组全部入堆,再出堆从后向前插入回数组中,数组就从小到大有序了. public class MaxHeap<T extends Comparable<? super T ...
- Object.defineProperty实现数据绑定
1.Object.defineProperty方法 Object.defineProperty(obj, prop, descriptor); (1)参数: obj:目标对象 prop:需要定义的属 ...
- redis的主从复制(读写分离)/哨兵(主从切换)配置
准备两个redis服务,两台机器,依次命名文件夹子master,slave1 10.10.10.7 10.10.10.8 1.master修改配置文件 [root@db2 conf]# cat 637 ...
- EF Core利用Transaction对数据进行回滚保护
What? 首先,说一下什么是EF Core中的Transaction Transaction允许以原子方式处理多个数据库操作,如果事务已提交,则所有操作都应用于数据库,如果事务回滚,则没有任何操作应 ...
- salesforce lightning零基础学习(一) lightning简单介绍以及org开启lightning
lightning对于开发salesforce人员来说并不陌生,即使没有做过lightning开发,这个名字肯定也是耳熟能详.原来的博客基本都是基于classic基于配置以及开发,后期博客会以ligh ...