mina学习总结

一、简介:

Apache Mina Server 是一个网络通信应用框架,Mina 可以帮助我们快速开发高性能、高扩展性的网络通信应用,Mina 提供了事件驱动、异步(Mina 的异步 IO 默认使用的是 JAVA NIO 作为底层支持)操作的编程模型。

二、使用示例:

 

三、体系结构:

 

1. IoService

负责具体的IO相关工作。IOService的意义在于隐藏底层IO的细节,对上提供统一的基于事件的异步IO接口。每当有数据到达时,IOService会先调用底层IO接口读取数据,封装成IoBuffer,之后以事件的形式通知上层代码;从图上看,进来的low-level IO经过IOService层后变成IO Event

在服务端的接口是IoAcceptor,具体实现类是NioSocketAcceptor,对应客户端的接口是IoConnector,实现类是NioSocketConnector;

2. IoFilterChain

Mina的设计理念之一就是业务代码和数据包处理代码分离,业务代码只专注于业务逻辑,其他的逻辑如:数据包的解析,封装,过滤等则交由IoFilterChain来处理。开发者通过往Chain中添加IoFilter,来增强处理流程,而不会影响后面的业务逻辑代码。

3. IoHandler

实现业务逻辑的地方,需要有开发者自己来实现这个接口;对于Server端和Client端来说都是IoHandler接口的实现类;在Mina中提供了IoHandler的实现类IoHandlerAdapter,业务逻辑代码类只需要继承这个类即可;

 

4. IoSession

一个IoSession对应于一个底层的IO连接,通过IoSession,可以获取当前连接相关的上下文信息,以及向远程peer发送数据。发送数据其实也是个异步的过程。发送的操作首先会逆向穿过IoFilterChain,到达IoService。但IoService上并不会直接调用底层IO接口来将数据发送出去,而是会将该次调用封装成一个WriteRequest,放入sessionwriteRequestQueue中,最后由IoProcessor线程统一调度flush出去。所以发送操作并不会引起上层调用线程的阻塞。

 

四、源码分析:

(一)服务端Service结构图:

  

1、IoService接口负责具体的IO相关工作。IOService的意义在于隐藏底层IO的细节,对上提供统一的基于事件的异步IO接口,并且接收客户端的连接并处理的组件;

2、AbstractIoService实现了IoService接口,作为服务端的抽象服务类,executeor作为Acceptor线程类执行的线程池(Acceptor线程用于监听端口、接收客户端连接、创建Session并交由Processor来处理);handler保存了用户业务逻辑处理的对象,过滤链的最后一个过滤器就是指向这个handler来处理的;sessionConfig表示session的配置信息,这个类用于所有session的初始配置信息,每当有客户端连接进来创建session时,就用这个配置来初始化session的配置信息;

3、AbstractIoAcceptor派生自AbstractIoService类,提供的defaultLocalAddresses用于绑定端口进行监听的;

4、AbstractPollingIoAcceptor派生自AbstractIoAcceptor,里面有一个Processor的池子,每一个session的业务处理都会交给其中一个Processor来处理;

5、NioSocketAcceptor派生自AbstractPollingIoAcceptorselector表示NIO的选择器,这个类里面主要实现了服务端口的绑定、打开channel、打开选择器、注册选择器到channel上、监听等待客户端连接等操作;

(二)初始化NioSocketAcceptor流程:

 

1、代码new一个NioSocketAcceptor对象,NioSocketAcceptor的构造函数交给父类AbstractPoolingIoAcceptorAbstractPoolingIoAcceptor的构造函数首先创建SimpleIoProcessorPool的处理器池对象;

2、SimpleIoProcessorPool是一个IoProcessor的池子,每个IoProcessor执行时又都是一个线程对象,需要一个线程池来调度这些线程,因此SimpleIoProcessorPool的构造函数会首先判断是否从外面传递了线程池executor对象进来,如果没传则创建新的线程池对象(newCachedThreadPool);接下来会创建cpu核数+1IoProcessor对象放置到处理器池中;

3、处理器池创建完成后就会调用NioSocketAcceptor.Init方法来完成初始化,init方法中只是调用Selector.open来打开选择器;

4、AbstractPoolingIoAcceptor创建完成并返回后,NioSocketAcceptor调用DefaultSocketSessionConfig.init来完成Session的配置的默认初始化;最后返回创建完成的NioSocketAcceptor对象给创建者;

(三)绑定端口并接收客户端连接流程:

 

1、客户端调用NioSocketAcceptor.bind在服务器绑定指定端口,这个bind会传递给父类AbstractIoAcceptor.bind来处理,然后他又调用子类AbstractPoolingIoAcceptor.bindInternal来处理,在这里创建Acceptor线程对象并交由线程池对象executor来执行;

2、Acceptor线程里面首先调用selector.select()打开选择器,然后调用ServerSocketChannel.open打开服务端channel,设置channel的相关属性(比如非阻塞configureBlockingReuseAddress等),ServerSocket.bind绑定端口监听,在channel上注册选择器Selector

3、上面的 NIO初始化操作完成后,最后调用ServerSocketChannel.accept()等待客户端连接,此时线程会阻塞,到这里服务端的绑定操作完成;

4、当有客户端连接请求到达时,上面的accept阻塞会返回,然后根据与客户端连接的socketChannel创建NioSocketSession对象并初始化这个sessionNioSocketSession对象会关联AbstractPollingIoAcceptorProcessorPool对象,这个ProcessorPool是在构造函数里面传入的);

5、接下来会根据session来选择对应的Processor对象(选择的方法是拿sessionIdProcessorPool的个数取余作为下标,然后用这个下标到ProcessorPool里面去取Processor对象),然后将该session添加到Processor要处理的session列表里面(processor对象里面维护着一个session队列——newSessions变量);

6、最后调用startupProcessor方法来处理该Processor对象管理的session请求;

(四)处理客户端请求(startupProcessor)流程:

 

1、startupProcessor创建内部Processor线程对象并交由线程池对象executor执行,首先selector.select阻塞到有事件就绪才继续往下执行;

2、循环遍历processor管理的所有session,给session注册OP_READ事件,构造session的过滤链FilterChain

3、然后在channel上读取数据到buffer,最后调用filterChain.fireMessageReceived将接收到的消息经过过滤链传递给业务逻辑处理handler来处理,如果发生异常,则调用filterChain.fireExceptionCaught经由过滤链传递给业务逻辑处理handler来处理异常;同样write方法与Read类似,只是在经过过滤器链时的顺序是相反的;

posted on 2018-03-26 16:26  小夏coding  阅读(368)  评论(0编辑  收藏  举报

导航