Mina实现流程

lhwyflyl01

贡献于2014-06-21

字数:4123 关键词: 网络工具包 Apache MINA

二.Mina 一个请求的主要实现流程: 服务器启动时,构造NioSocketAcceptor,服务器同时也会构造NioProcessor。 client请求->NioSocketAcceptor建立连接,在bind监听端口后,调用startupAcceptor()方法->接收线程Acceptor启动->processHandles()方法调用->初始化session,并把session加入到NioProcessor待处理session队列中。 当始化session时,NioProcessor已经在通道中注册可读事件,同时add(T session)方法调用后->启动startupProcessor()方法->处理线程Processor启动->然后读事件读取数据时会在通道中执行过滤器连。 如果有相应的业务处理,则调用相应的IoHandler(),然后组织返回给client的数据,经过数据经过滤连,数据发出。   一般我们自己写nio服务器端时,只有一个selector,但mina框架使用了两个选择器selector,其中一个用来建立连接,其核心为NioSocketAcceptor 另一个负责读写事件的,其核心为NioProcessor   三.NioSocketAcceptor相关说明 1.NioSocketAcceptor的父类为AbstractPollingIoAcceptor,很多实现是在父类中实现的。在构造此类的时候,同时也构造了NioProcessor类,代码如下: protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig, Class> processorClass) { this(sessionConfig, null, new SimpleIoProcessorPool(processorClass), true); } 并且NioProcessor的个数为cpu+1, private static final int DEFAULT_SIZE = Runtime.getRuntime() .availableProcessors() + 1; 2.init方法,打开selector通道;aceeptor()方法处理接收连接,把SocektChannel绑定到NioSession中;open()方法是打开serversocketchannel,然后配制socket的一些基本属性,并注册此事件是可连接的事件。 socket.bind(localAddress, getBacklog()); // Register the channel within the selector for ACCEPT event channel.register(selector, SelectionKey.OP_ACCEPT);   3.父类中有内部线程类Acceptor,主要负责轮询处理注册过连接事件的请求建立起连接。此线程类是在startupAcceptor()方法中调用,代码如下: private void startupAcceptor() { // If the acceptor is not ready, clear the queues // TODO : they should already be clean : do we have to do that ? if (!selectable) { registerQueue.clear(); cancelQueue.clear(); }   // start the acceptor if not already started synchronized (lock) { if (acceptor == null) { acceptor = new Acceptor(); executeWorker(acceptor); } } }   四.NioProcessor相关说明: 1.NioProcessor 在接收连接之后,另开了一个selector,用来处理读写事件。其大部分功能,在父类AbstractPollingIoProcessor中实现   2.Mina中用NioSession来封装了channel对应的读写操作等功能.   3.在NioProcessor类中init方法为: protected void init(NioSession session) throws Exception { SelectableChannel ch = (SelectableChannel) session.getChannel(); ch.configureBlocking(false); session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ, session)); } 很明显注册了读事件,并与相应的NioSession对应起来。   4.在NioProcessor类中表面上看代码好像没有注册过写事件,而且实际应用中,读写事件是来回切换的。但是实际上NioProcessor用另外的方法实现了: setInterestedInRead() setInterestedInWrite() 这两个方法通过key.interestOps(newInterestOps)来实现事件切换,从而达到了注册读写事件的作用。 要明白读写注册事件,首先得明白SocketChannel注册事件的原理,一个通道每次注册时只对应一个事件,而每次注册不同事件时,只是对此通道的事件进行了切换而已。所以通过key.interestOps(ops)方法是实现了最原始的操作,即切换通道事件。   5.NioSession中read与write方法同Buffer中一样。   6.IoSessionIterator an encapsulating iterator 。是NioProcess一个内部类 实现了iterator 接口的类,主要是重写了其方法public NioSession next(),目的是把迭代key时,把NioSession取出。 public NioSession next() { SelectionKey key = iterator.next(); NioSession nioSession = (NioSession) key.attachment(); return nioSession; } 五.NioProcessor 父类AbstractPollingIoProcessor的相关实现: 1.Processor,为父类的内部线程类,在startProcessor()方法调用,通过executor启动此线程。一般请求在NioSocketAcceptor上建立连接后,然后启动NioProcessor中的工作线程Processor。一般也不是马上企动的,需要在调用addNew方法后,有新的请求后才会调用。   2.此类中有四个ConcurrentLinkedQueue分别用来存储创建,删除,操作中的session。其中值的说明的是flushingSessions是用来写session的   3.executor为NioProcessor工作线程,默认实现为:Executors.newCachedThreadPool()来定义。   4.startupProcessor()方法,开始工作线程,此处把processor内部线程类放入线程池中运行。如果select()出现阻塞,才马上唤醒,在processor线程每次select时间为一秒 private void startupProcessor() { synchronized (lock) { if (processor == null) { processor = new Processor(); executor.execute(new NamePreservingRunnable(processor, threadName)); } }   // Just stop the select() and start it again, so that the processor // can be activated immediately. wakeup(); }   5.handNewSessions(T session) 从新session队列中取出所有待处理的session.然后通过addNow(T Session)给session init(),buildfilterchain过滤这些等。最后返回处理了session的数量。另外也有对应的removeSession()方法   6.read(T session)是读取session里面的数据。如果读取数据的容易超过初始时设定的buffer大小时buffer会自动增加。写数据是通过writeBuffer()方法实现,往外写数据buffer大小也自动增加。 在此处要说明的,在此调用的read与writebuffer方法并不是最上层的方法,而是通过firechain连,调用fireMessageReceived(buf),以及fireMessageSent(session,buf)来读写。 请求到达时实例IoProcessor在会话通道中会执行过滤器链。 另外,如果此请求还有逻辑处理的话,接着也会执行相应的IoHandler。   六.Mina中IoProcessor处理方式 Mina 默认的线程工作方式为一个IoProcessor 负责执行一个会话上的所有过滤器、IoHandler,也就是对于IO 读写操作来说,是单线程工作方式(就是按照顺序逐个执行)。假如你想让某个事件方法(譬如:sessionIdle()、sessionOpened()等)在单独的线程中运行(也就是非IoProcessor 所在的线程),那么这里就需要用到一个ExecutorFilter 的过滤器。 增加一个ExecutorFilter代码如下: acceptor.getFilterChain().addLast("exceutor", new ExecutorFilter()); 对于ExecutorFilter默认线程实现方式也可以修改。

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 5 金币 [ 分享文档获得金币 ]
0 人已下载

下载文档

相关文档