一起来读Netty In Action(一)

2018-06-18 00:56:14来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

    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和编程模型的基本知识。

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:备忘录模式-Memento Pattern(Java实现)

下一篇:JAVAEE——Mybatis加强:输入和输出映射、动态sql、关联查询、My