文档章节

第十六章:从EventLoop取消注册和重新注册

土茯苓
 土茯苓
发布于 2016/09/27 09:51
字数 1275
阅读 29
收藏 2

本章介绍

EventLoop

从EventLoop注册和取消注册

在Netty中使用旧的Socket和Channel

Netty提供了一个简单的方法来连接Socket/Channel,这是在Netty之外创建并转移他们的责任到Netty。这允许你将遗留的集成框架以无缝方式一步一步迁移到Netty;Netty还允许取消注册的通道来停止处理IO,这可以暂停程序处理并释放资源。

这些功能在某些情况或某种程度上可能不是非常有用,但使用这些特性可以解决一些困难的问题。举个例子,有一个非常受欢迎的社交网络,其用户增长非常快,系统程序需要处理每秒几千个交互或消息,如果用户持续增长,系统将会处理每秒数以万计的交互;这很令人兴奋,但随着用户数的增长,系统将消耗大量的内存和CPU而导致性能低下;此时最需要做的就是改进他们,并且不要花太多的钱在硬件设备上。这种情况下,系统必须保持功能正常能处理日益增长的数据量,此时,注册/注销事件循环就派上用场了。

通过允许外部Socket/Channel来注册和注销,Netty能够以这样的方式改进旧系统的缺陷,所有的Netty程序都可以通过一种有效精巧的方式整合到现有系统,本章将重点讲解Netty是如何整合。

16.1 注册和取消注册的Channel和Socket

前面章节讲过,每个通道需要注册到一个EventLoop来处理IO或事件,这是在引导过程中自动完成。下图显示了他们的关系:

上图只是显示了他们关系的一部分,通道关闭时,还需要将注册到EventLoop中的Socket/Channel注销以释放资源。

有时不得不处理java.nio.channels.SocketChannel或其他java.nio.channes.Channel实现,这可能是遗留程序或框架的一些原因所致。我们可以使用Netty来包装预先创建的java.nio.channels.Channel,然后再注册到EventLoop。我们可以使用Netty的所有特性,同时还能重用现有的东西。下面代码显示了此功能:

//nio  
java.nio.channels.SocketChannel mySocket = java.nio.channels.SocketChannel.open();  
//netty  
SocketChannel ch = new NioSocketChannel(mySocket);  
EventLoopGroup group = new NioEventLoopGroup();  
//register channel  
ChannelFuture registerFuture = group.register(ch);  
//de-register channel  
ChannelFuture deregisterFuture = ch.deregister();

Netty也适用于包装OIO,看下面代码:

//oio  
Socket mySocket = new Socket("www.baidu.com", 80);  
//netty  
SocketChannel ch = new OioSocketChannel(mySocket);  
EventLoopGroup group = new OioEventLoopGroup();  
//register channel  
ChannelFuture registerFuture = group.register(ch);  
//de-register channel  
ChannelFuture deregisterFuture = ch.deregister();  

只有2个重点如下:

    使用Netty包装已创建的Socket或Channel必须使用与之对应的实现,如Socket是OIO,则使用Netty的OioSocketChannel;SocketChannel是NIO,则使用NioSocketChannel。

    EventLoop.register(...)和Channel.deregister(...)都是非阻塞异步的,也就是说它们可能不会理解执行完成,可能稍后完成。它们返回ChannelFuture,我们在需要进一步操作或确认完成操作时可以添加一个ChannelFutureLister或在ChannelFuture上同步等待至完成;选择哪一种方式看实际需求,一般建议使用ChannelFutureLister,应避免阻塞。

16.2 挂起IO处理

在一些情况下可能需要停止一个指定通道的处理操作,比如程序耗尽内存、崩溃、失去一些消息,此时,我们可以停止处理事件的通道来清理系统资源,以保持程序稳定继续处理后续消息。若这样做,最好的方式就是从EventLoop取消注册的通道,这可以有效阻止通道再处理任何事件。若需要被取消的通道再次处理事件,则只需要将该通道重新注册到EventLooop即可。看下图:

看下面代码:

EventLoopGroup group = new NioEventLoopGroup();  
Bootstrap bootstrap = new Bootstrap();  
bootstrap.group(group).channel(NioSocketChannel.class)  
        .handler(new SimpleChannelInboundHandler<ByteBuf>() {  
            @Override  
            protected void channelRead0(ChannelHandlerContext ctx,  
                    ByteBuf msg) throws Exception {  
                //remove this ChannelHandler and de-register  
                ctx.pipeline().remove(this);  
                ctx.deregister();  
            }  
        });  
ChannelFuture future = bootstrap.connect(  
        new InetSocketAddress("www.baidu.com", 80)).sync();  
//....  
Channel channel = future.channel();  
//re-register channel and add ChannelFutureLister  
group.register(channel).addListener(new ChannelFutureListener() {  
    @Override  
    public void operationComplete(ChannelFuture future) throws Exception {  
        if(future.isSuccess()){  
            System.out.println("Channel registered");  
        }else{  
            System.out.println("register channel on EventLoop fail");  
            future.cause().printStackTrace();  
        }  
    }  
});  

16.3 迁移通道到另一个事件循环

另一个取消注册和注册一个Channel的用例是将一个活跃的Channel移到另一个EventLoop,有下面一些原因可能导致需要这么做:

当前EventLoop太忙碌,需要将Channel移到一个不是很忙碌的EventLoop;

终止EventLoop释放资源同时保持活跃Channel可以继续使用;

迁移Channel到一个执行级别较低的非关键业务的EventLoop中。

下图显示迁移Channel到另一个EventLoop:

看下面代码:

EventLoopGroup group = new NioEventLoopGroup();  
final EventLoopGroup group2 = new NioEventLoopGroup();  
Bootstrap b = new Bootstrap();  
b.group(group).channel(NioSocketChannel.class)  
        .handler(new SimpleChannelInboundHandler<ByteBuf>() {  
            @Override  
            protected void channelRead0(ChannelHandlerContext ctx,  
                    ByteBuf msg) throws Exception {  
                // remove this channel handler and de-register  
                ctx.pipeline().remove(this);  
                ChannelFuture f = ctx.deregister();  
                // add ChannelFutureListener  
                f.addListener(new ChannelFutureListener() {  
                    @Override  
                    public void operationComplete(ChannelFuture future)  
                            throws Exception {  
                        // migrate this handler register to group2  
                        group2.register(future.channel());  
                    }  
                });  
            }  
        });  
ChannelFuture future = b.connect("www.baidu.com", 80);  
future.addListener(new ChannelFutureListener() {  
    @Override  
    public void operationComplete(ChannelFuture future)  
            throws Exception {  
        if (future.isSuccess()) {  
            System.out.println("connection established");  
        } else {  
            System.out.println("connection attempt failed");  
            future.cause().printStackTrace();  
        }  
    }  
});  

 

 

 

© 著作权归作者所有

共有 人打赏支持
土茯苓
粉丝 32
博文 174
码字总数 198211
作品 0
朝阳
高级程序员
私信 提问
微信公众平台完整开发教程(系列教程)每天更新一章(详情看目录)想让继续更新的留个言

微信已然成了一种生活方式:群聊、语音、视频,照片/视频/位置共享,支付和商店有了,还能通过公众账号来获取各种资源……如今的微信就是在日中天的状态(最新估值已达 600 亿),公众平台带...

MIANMIANLIFE
2015/12/17
3.5K
3
Netty 源码分析(三):服务器端的初始化和注册过程

简介 接下来我们会通过使用 Netty 去实现 NIO TCP 服务器的这个场景来解析 Netty 的源代码,深入了解 Netty 的设计。 使用 Netty 来实现一个 TCP 服务器,我们大致要做以下事情: 创建 Serv...

编走编想
2015/10/20
0
0
小白带你认识netty(二)之netty服务端启动(下)

承接上一篇小白带你认识netty(二)之netty服务端启动(上),还剩下两步骤:3、注册Selector:将Channel注册到Selector上 和 4、端口的绑定:服务端端口的监听。 3、注册Selector:将Chann...

天空小小
2018/11/18
0
0
Netty 4.0源码分析1:服务端启动过程中的Channel与EventLoopGroup的注册

启动服务端的代码如下: public static void main(String[] args) throws Exception { SelfSignedCertificate ssc = new SelfSignedCertificate(); SslContext sslCtx = SslContext.newServe......

cdzwmlcl
2015/03/31
0
3
Netty源码分析(一)概览

准备将Netty的源码过一下,一来对自己是个总结消化的过程,二来希望对那些打算看Netty源码的人(已经熟悉Netty的Reactor模型)能有一些帮助。目前所看Netty版本是4.1.3.Final。 1 目录 - Ne...

乒乓狂魔
2016/08/17
334
0

没有更多内容

加载失败,请刷新页面

加载更多

Linux iptables之mangle表使用案例

mangle表的用途 mangle表的主要功能是根据规则修改数据包的一些标志位,以便其他规则或程序可以利用这种标志对数据包进行过滤或策略路由。 mangel表使用示例 示例1-策略路由1 内网的客户机通...

月下狼
34分钟前
2
0
OSChina 周日乱弹 —— 兼职我想去学学布偶戏

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @clouddyy : 《火炎 - 女王蜂》 《火炎 - 女王蜂》 手机党少年们想听歌,请使劲儿戳(这里) @小鱼丁 :还在睡觉突然接到一个小哥哥电话“x...

小小编辑
47分钟前
42
3
租房软件隐私保护如同虚设

近日,苏州市民赵先生向江苏新闻广播新闻热线025-84658888反映,他在“安居客”手机应用软件上浏览二手房信息,并且使用该软件自动生成的虚拟号码向当地一家中介公司进行咨询。可电话刚挂不久...

linux-tao
今天
3
0
分布式项目(五)iot-pgsql

书接上回,在Mapping server中,我们已经把数据都整理好了,现在利用postgresql存储历史数据。 iot-pgsql 构建iot-pgsql模块,这里我们写数据库为了性能考虑不在使用mybatis,换成spring jd...

lelinked
今天
6
0
一文分析java基础面试题中易出错考点

前言 这篇文章主要针对的是笔试题中出现的通过查看代码执行结果选择正确答案题材。 正式进入题目内容: 1、(单选题)下面代码的输出结果是什么? public class Base { private Strin...

一看就喷亏的小猿
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部