java NIO的多路复用及reactor模式【转载】

本文转载自:http://www.blogjava.net/hello-yun/archive/2012/10/17/389729.html

java nio从1.4版本就出现了,而且依它优异的性能赢得了广大java开发爱好者的信赖。我很纳闷,为啥我到现在才接触,难道我不是爱好者,难道nio不优秀。经过长达半分钟的思考,我意识到:时候未到。以前总是写那些老掉牙的web程序,唉,好不容易翻身啦,现在心里好受多了。因为真不想自己到了30岁,还在说,我会ssh,会ssi,精通javascript,精通数据库,精通。。。人生苦短,要开拓点不是吗?列为兄弟姐妹,没看到外国的和尚已经开始鼓吹“云里雾里”的?没看到百度进入“框”啦,没看到oracle的“格”啦。人家的经,随他念,但是我们的确有好多路要走哦(牢骚怎么这么多呀)。

现在终于到了我了解nio的时候了,突然发现有很多美妙程序的源码,不得不爽一把(有邪念者,该打住啦,像我这样)。

以下描述,为了说明问题,就提提历史(类似的东西,网上一搜一大把,但是希望你能在这里止步,知道到底是怎么回事。如果还是不清楚,咱就站内沟通!)。

在我(刚)看nio的这段时间里,主要接触了几个东西,就是关于server和client。java之前的io完全可以胜任,但是效率不高,为何效率不高呢?

===============history==start===============

//TODO:finish the old style of server and socket data transion.

ServerSocket socket = new ServerSocket(80); 
        while (true) { 
            final Socket connection = socket.accept(); 
            handleRequest(connection); 
        }

===============history==end in the future================

在上面的代码片段中,我们只能是一个request一个的进行处理。这使得所有的请求都阻塞了。如果我们再改变一下,将handleRequest方法封装到线程中处理:

if(connection = null){

new Thread(new Runnable(){

public void run(){

handleRequest(connection);

}

public void handleRequest(Socket conn){

//do actions

}

}).start();

}

服务器端的资源是有限的,我们这里仅仅是从线程角度来扩展,但是这种处理依然是阻塞的处理方式。首先,仅仅是建立连接(socket),就占用了服务器的线程资源。如果客户端还没有发出相应的数据请求,那么服务器就要一直等待他们的数据流过来,然后再进行读取,如此往复。。。一直都blocking。服务器处在一个高负荷状态中。

NIO出来之后,进入改革开放时期,有了这么几个角色,ServerSocketChannel,SelectionKey,Selector.

这几个角色都是做什么用的呢?需要了解一下reactor模式(反应堆模式)。

作为服务端,如果什么操作都要依赖于客户端,很多操作都阻塞,如上面的代码片段所示。reactor模式提供了一种很好的事件处理机制,以分离事件处理对象与事件之间的耦合。如下图示(详细请看参考资料(1)):

说明:

Acceptor就是我们Server端的主要任务消化者;

Initiation Dispatcher是事件(Event)的分发者;

HTTP Handler是具体操作人。

首先,在Initiation Dispatcher中注册一个acceptor(1:register Acceptor),这个Acceptor是跟事件绑定的,它仅仅关心某种事件(event)。

Initiation Dispatcher不断地循环获取请求过来的事件(2:handle events),如果发现有对应Acceptor关心的事件(3:connect),通知Acceptor有事件发生(4:new connection)。

Acceptor针对此事件进行处理,创建了新的HTTP Handler((5:create handler))

一轮事件获取和分发完成。

那么handler是不是就抓住这个connection不放,然后一直苦苦等待数据流的到来呢?

不是的,它也是将自己和自己关心的事件注册到Initiation Dispatcher。如果Initiation Dispatcher在handle Events时发现了它关心的事件,那么就会交由它去进行相应处理。如下图示,在连接完成后,browser提交的get请求,handler的处理过程:

这里面尤其要注意到,2:read ready,之后才read request,也就是说,handler在dispatcher中注册了自己关心的事件(READ),然后在写的时候,也是类似情况。

以上的过程就实现了非阻塞的处理方式,客户端的连接可以非阻塞(这是意思是,acceptor不必一直苦苦等候),然后对客户端过来的request内容,也是非阻塞(这里是不必苦苦等待其数据的到来),都是不必一直眼巴巴的看着那个连接,那些数据,而是如果有我关心的事件了,我再进行处理,期间完全相信Initiation Dispatcher就行了。

这里有一点要注意,就是现在的reactor模式都是建立在操作系统的基础上实现的,不同的操作系统有不同的实现方式。而且都不支持多线程(针对Initiation Dispatcher而言)。

有了上面的理解之后,来给NIO中的对象跟reactor的对象对个象。

Acceptor:ServerSocketChannel;

Initiation Dispatcher:Selector;

HTTP Handler:针对SocketChannel进行实际处理的个性化对象;

Events:在SelectionKey中:

static int  OP_ACCEPT Operation-set bit for socket-accept operations.
static int  OP_CONNECT  Operation-set bit for socket-connect operations.
static int  OP_READ  Operation-set bit for read operations.
static int  OP_WRITE  Operation-set bit for write operations.

下一篇,NIO包中对象的介绍。有些本末倒置哦,但是,这篇里面没有用到很多api,主要是reactor明白了,非阻塞明白了,目的就达到了。经过上面的描述,我们就可以写出基于NIO的非阻塞Server啦。具体的代码示例大家可以看参考资料(2)。

参考资料:

(1)华盛顿大学计算机科学的一篇关于proactor的论文,非常详细。同时这篇文章中还有 reactor的改进版proactor,各位可以一饱眼福。

(2)简单的NIO server实现代码,但是这个代码中在写的部分有些瑕疵,各位根据上面的描述,可以考虑一下有何问题。

在这个代码中,还有一个要注意的地方,就it.remove(),因为某个key在处理过后要删除,否则,这个key将一直处于active状态。

时间: 2024-11-12 11:03:42

java NIO的多路复用及reactor模式【转载】的相关文章

IO多路复用和Reactor模式

1. Reactor和Preactor模式 Reactor用于同步IO,Preactor用于异步IO Reactor通常会和Connector模式一起使用,进一步解耦连接的建立与连接以后的逻辑 2. Reactor模式中的主要角色 2.1. Reactor Reactor是IO事件的派发者. 2.2. Acceptor Acceptor接受client连接,建立对应client的Handler,并向Reactor注册此Handler. 2.3. Handler 和一个client通讯的实体,按这

Java NIO实现的C/S模式多人聊天工具

小弟初学NIO,做了个控制台聊天工具,不知道代码写的如何,望大神们批评指点. 服务器端,两个线程,一个处理客户端请求和转发消息,另一个处理服务器管理员指令,上代码: package kindz.onlinechat; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.cha

IO多路复用之Reactor模式

首先,我们来看看同步和异步. 在处理 IO 的时候,阻塞和非阻塞都是同步 IO.只有使用了特殊的 API 才是异步 IO. 接下来,我们来看看Linux下的三大同步IO多路复用函数 fcntl(fd, F_SETFL, O_NONBLOCK);  //socket设为O_NONBLOCK,但是select/poll/epoll是block操作 1)select int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exce

Java多线程:Linux多路复用,Java NIO与Netty简述

JVM的多路复用器实现原理 Linux 2.5以前:select/poll Linux 2.6以后: epoll Windows: IOCP Free BSD, OS X: kqueue 下面仅讲解Linux的多路复用. Linux中的IO Linux的IO将所有外部设备都看作文件来操作,与外部设备的操作都可以看做文件操作,其读写都使用内核提供的系统调用,内核会返回一个文件描述符(fd, file descriptor),例如socket读写使用socketfd.描述符是一个索引,指向内核中一个

Java NIO中的Glob模式详解

Java NIO中的Glob模式详解 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs 一.什么是Glob? 在编程设计中,Glob是一种模式,它使用通配符来指定文件名.例如:.java就是一个简单的Glob,它指定了所有扩展名为"java"的文件.Glob模式中广泛使用了两个通配符""和"?".其中星号表示"任意的字符或字符组成字符串",而问号则表示"任意单个字符&quo

(转)reactor模式

转自: http://www.blogjava.net/DLevin/archive/2015/09/02/427045.html Reactor模式详解 前记 第一次听到Reactor模式是三年前的某个晚上,一个室友突然跑过来问我什么是Reactor模式?我上网查了一下,很多人都是给出NIO中的 Selector的例子,而且就是NIO里Selector多路复用模型,只是给它起了一个比较fancy的名字而已,虽然它引入了EventLoop概 念,这对我来说是新的概念,但是代码实现却是一样的,因而

Reactor模式详解

前记第一次听到Reactor模式是三年前的某个晚上,一个室友突然跑过来问我什么是Reactor模式?我上网查了一下,很多人都是给出NIO中的 Selector的例子,而且就是NIO里Selector多路复用模型,只是给它起了一个比较fancy的名字而已,虽然它引入了EventLoop概 念,这对我来说是新的概念,但是代码实现却是一样的,因而我并没有很在意这个模式.然而最近开始读Netty源码,而Reactor模式是很多介绍Netty的文章中被大肆宣传的模式,因而我再次问自己,什么是Reactor

Nio学习3——基础模型:Reactor模式和多路复用

Reactor模式和NIO 本文可看成是对Doug Lea Scalable IO in Java一文的翻译. 当前分布式计算 Web Services盛行天下,这些网络服务的底层都离不开对socket的操作.他们都有一个共同的结构: 1. Read request 2. Decode request 3. Process service 4. Encode reply 5. Send reply 经典的网络服务的设计如下图,在每个线程中完成对数据的处理: 但这种模式在用户负载增加时,性能将下降

Java进阶知识点5:服务端高并发的基石 - NIO与Reactor模式以及AIO与Proactor模式

一.背景 要提升服务器的并发处理能力,通常有两大方向的思路. 1.系统架构层面.比如负载均衡.多级缓存.单元化部署等等. 2.单节点优化层面.比如修复代码级别的性能Bug.JVM参数调优.IO优化等等. 一般来说,系统架构的合理程度,决定了系统在整体性能上的伸缩性(高伸缩性,简而言之就是可以很任性,性能不行就加机器,加到性能足够为止):而单节点在性能上的优化程度,决定了单个请求的时延,以及要达到期望的性能,所需集群规模的大小.两者双管齐下,才能快速构建出性能良好的系统. 今天,我们就聊聊在单节点