一起来读Netty In Action之异步和事件驱动(一)

news/2024/7/20 12:46:56 标签: netty, java, 内存管理

    Netty是一款异步事件驱动的网络应用程序框架,支持快速的开发可维护的高性能的面向协议的服务器和客户端。在网络编程中,阻塞、非阻塞、同步、异步经常被提到。同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?

    常见的I/O模型有如下几种:

 

我们举一个场景来说明上面各是什么意思:

   周末我和宝宝逛街,中午饿了,我们准备去吃饭。周末人多,吃饭需要排队,我和宝宝有以下几种方案:

(1)阻塞:我和宝宝点完餐后,不知道什么时候能做好,只好坐在餐厅里面等,直到做好,然后吃完才离开。宝宝本想还和我一起逛街的,但是不知道饭能什么时候做好,只好和我一起在餐厅等,而不能去逛街,直到吃完饭才能去逛街,中间等待做饭的时间浪费掉了。这就是典型的阻塞。

(2)非阻塞:宝宝不甘心白白在这等,又想去逛商场,又担心饭好了。所以我们逛一会,回来询问服务员饭好了没有,来来回回好多次,饭都还没吃都快累死了啦。这就是非阻塞。需要不断的轮询,是否准备好了。

(3)多路复用:与第二个方案差不多,餐厅安装了电子屏幕用来显示点餐的状态,这样我和宝宝逛街一会,回来就不用去询问服务员了,直接看电子屏幕就可以了。这样每个人的餐是否好了,都直接看电子屏幕就可以了,这就是典型的IO多路复用,如select、poll、epoll。

(4)异步:宝宝不想逛街,又嫌餐厅太吵了,想好好休息一下。于是我们叫外卖,打个电话点餐,然后我和宝宝可以在家好好休息一下(此处忽略带宝宝回家的细节),饭好了送货员送到家里来。这就是典型的异步,只需要打个电话说一下,然后可以做自己的事情,饭好了就送来了。

所以阻塞非阻塞的区别在于:简单理解为需要做一件事能不能立即得到返回应答,如果不能立即获得应答,需要等待,那就阻塞了,否则就可以理解为非阻塞。 

而其实同步和异步的区别:就是在线程在等待的过程中能不能去做另外的事情,如果是同步,则线程一直等待或者去轮询结果;如果是异步,线程直接返回,去做其他的工作,而本次I/O完成之后会主动通知线程完成。实际上同步与异步是针对应用程序与内核的交互而言的。同步过程中进程触发IO操作并等待或者轮询的去查看IO操作是否完成。异步过程中进程触发IO操作以后,直接返回,做自己的事情,IO交给内核来处理,完成后内核通知进程IO完成。

其实我们经常用的ajax就是异步的JavaScriptXML技术,在jquery中我们可以配置async: false属性设置ajax为同步请求,其实在js处理处理ajax的时候,会开启单独的ajax工作线程来处理请求,随后,主线程就去做其他的事情了,在主线程收到该请求的回调通知的时候,他才会回来处理该请求结果。

 

下面两幅图展示了java网络编程中的阻塞I/O和java nio提供的非阻塞I/O的模型:

 

                     使用阻塞I/O处理多个连接                             使用selector的非阻塞I/O

使用selector的模型有如下的好处:

    (1)较少的线程处理许多连接,减少内存管理和上下文切换带来的开销。

    (2)没有I/O需要处理的时候,线程也可以被用于其他任务。

 

介绍完这些概念,我们来看一下netty有哪些核心构件吧。

 

1.channel

channel是java NIO的一个基本构造,代表着一个到实体的开发连接,如读操作和写操作。Channel通道和流非常相似,主要有以下几点区别:

  • 通道可以读也可以写,流一般来说是单向的(只能读或者写)。
  • 通道可以异步读写。
  • 通道总是基于缓冲区Buffer来读写。

java中channel有如下的实现:

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel

FileChannel用于文件的数据读写。 DatagramChannel用于UDP的数据读写。 SocketChannel用于TCP的数据读写。 ServerSocketChannel允许我们监听TCP链接请求,每个请求会创建会一个SocketChannel.所以ServerSocketChannel并不传输数据。

 

2.回调

一个回调其实就是一个方法。在netty内部使用了回调来处理事件,当一个回调被触发,相关的事件可以被ChannelHandler的实现处理。

3.Future

Future提供了另一种在操作完成时通知应用程序的方式,它提供了对此次异步操作的的结果的访问。在java的concurrent包下的 Future只允许手动的检查对应的操作是否已经完成,或者一直阻塞到它完成,所以netty提供了它的实现-channelFuture用于在执行异步的时候调用。channelFuture还提供了额外的方法这些方法使得我们能够注册一个或者多个channelFutureListener 实例,这些监听器的回调方法:operationComplete(),将会在对应的操作完成时被调用每个netty的出站I/O操作都会返回一个ChannelFuture,如下代码中connect ()方法将会直接返回,不会阻塞。

 

1 Channel channel = ...;
2 ChannelFuture future = channel.connect(new InetSocketAddress("192.168.0.1",25)); //异步的连接到远程节点

 

下面的例子展示了ChannelFuture和回调的用法:

 1 Channel channel = ...;
 2 ChannelFuture future = channel.connect(new InetSocketAddress("192.168.9.1",25));  //异步连接到远程节点
 3 future.addListener(new ChannelFutureListener(){    //注册一个ChannelFutureListener,以便在操作完成时获得通知
 4      @Override
 5      public void operationComplete(ChannelFuture future){
 6               if(future.isSuccess()){    //如果操作是成功的,执行相应的操作
 7                 //...
 8 
 9          }else{
10             Throwable cause = future.cause();   //操作失败的异常处理
11             cause.printStackTrace();
12          }
13      }
14 });

 

其实可以把ChannelFutureListener看作是回调的一个更加精细的版本。回调和ChannelFutureListener相互补充,构成netty最为关键的组件之一。

 

4.事件和channelHandler

netty使用不同的事件开通知我们状态的改变或者是操作的状态,可能由入站数据或者相关的状态更改而触发的事件包括:

    (1)连接激活或者连接失活

    (2)数据读取

    (3)用户事件

    (4)错误事件

出站事件是未来将会触发的某个动作的操作结果,这些动作包括:

    (1)打开或者关闭到远程节点的连接。

    (2)将数据写到或者冲刷到套接字。

每个事件都可以被分发到ChannelHandler类中的某个用户实现的方法,下图展示了ChannelHandler链是怎么处理入站事件的(出站事件也是一样的):

 

netty的ChannelHandler为处理器提供了基本的抽象,netty也提供了大量的预定义的可以开箱即用的ChannelHandler 实现,包括用于各种协议的(如http或ssl/tls)的 ChannelHandler,在内部,ChannelHandler自己也使用了事件和future。

5.总结

 netty通过触发事件将selector从应用程序抽象出来,消除了所有本来将需手动编写的派发代码,在内部,将会为每个Channel分配一个EventLoop,用于处理所有的事件,包括:

     (1)注册感兴趣的事件

     (2)将事件派发给ChannelHandler

     (3)安排进一步的动作

EventLoop本身只由一个线程驱动,其处理了一个channel的所有的I/O事件,并且在该channel整个生命周期内都不会变,这种设计消除了可以在你的ChannelHandler中需要进行同步的顾虑。

下一节我们将深入的探讨netty的API和编程模型的基本知识。

转载于:https://www.cnblogs.com/jy107600/p/8745677.html


http://www.niftyadmin.cn/n/1188949.html

相关文章

android fragment 中动画不显示_在Fragment之间导航时使用动画

片段API提供了两种使用运动效果和变换的方式,以在导航过程中直观地连接片段。其中之一是动画框架,它同时使用 Animation和 Animator。另一个是“过渡框架”,其中包括共享元素过渡。注意:在本主题中,我们使用术语动画描…

JS设置CSS样式的集中方式

1. 直接设置style的属性 某些情况用这个设置 !important值无效 如果属性有-号,就写成驼峰的形式(如textAlign) 如果想保留 - 号,就中括号的形式 element.style[text-align] 100px; element.style.height 100px; 2. 直接设置属…

发那科机器人初始化步骤_FANUC机器人保养步骤--R-2000iB

相信大家都会对自己的爱车做定期的大小保养,其实机器人也需要定期做保养,下面放出R-2000iB机器人的三年保养的操作流程,无论是否自己动手,了解一下准没有错!保养周期 :1. 当正常使用的机器人运行时间达到1万…

oracle 添加归档日志文件_Oracle归档日志分析

本记录仅供自己使用,有看不懂的朋友莫见怪,后期会做相应补充。本机操作系统:win10服务器操作系统:Linux服务器数据库:Oracle一、找到日志文件1、通过Xshell 6远程连接服务器,登录相应账户:su or…

游程编码用matlab实现代码_哈夫曼编码MATLAB实现

在计算机数据处理中,霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现几率的方法得到的,出现几率高的字母使用较短的编码,反之出现几率低的则使用…

垂直广告是什么意思_葡萄酒品鉴会中的垂直品鉴和水平品鉴都是什么意思?

这些年来,每个城市每年都时不时的会有葡萄酒有关的品鉴会出现,或许我们没有参加过,但至少喜欢葡萄酒的朋友会看到这样的讯息,特别是在进口葡萄酒方面,经常会有某某酒庄或某某品牌搞了垂直品鉴会,或者某某产…

计蒜客 跳跃游戏2

给定一个非负整数数组,假定你的初始位置为数组第一个下标。数组中的每个元素代表你在那个位置能够跳跃的最大长度。你的目标是到达最后一个下标,并且使用最少的跳跃次数。例如:A [2,3,1,1,4]A[2,3,1,1,4],到达最后一个下标的最少…

商城项目中信息的集合怎么存储_存储过程在网上商城系统开发中的应用

龙源期刊网http://www.qikan.com.cn存储过程在网上商城系统开发中的应用作者:吴伶琳来源:《计算机时代》2013年第09期摘要:存储过程是数据库端执行的一组T-SQL语句的集合。网上商城系统具有大量的用户交互的特点,系统性能十分重要…