MINA2实用手册
- 格式:docx
- 大小:48.26 KB
- 文档页数:17
MINA2实用手册
作者:李庆丰
Email:scholers@
MINA框架是对java的NIO包的一个封装,简化了NIO程序开发的难度,封装了很多底层的细节,然开发者把精力集中到业务逻辑上来,最近做了一个相关的项目,为了备忘对MINA做一个总结。
一、 服务端初始化及参数配置
MINA2初始化很简单。
基本的初始化参数如下:
//初始化Acceptor—可以不指定线程数量,MINA2里面默认是CPU数量+2
NioSocketAcceptor acceptor = new NioSocketAcceptor(5);
java.util.concurrent.Executor threadPool =
Executors.newFixedThreadPool(1500);//建立线程池
//加入过滤器(Filter)到Acceptor
acceptor.getFilterChain().addLast("exector", new
ExecutorFilter(threadPool));
//编码解码器
acceptor.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new WebDecoder(),new
XmlEncoder()));
//日志
LoggingFilter filter = new LoggingFilter();
filter.setExceptionCaughtLogLevel(LogLevel.DEBUG);
filter.setMessageReceivedLogLevel(LogLevel.DEBUG);
filter.setMessageSentLogLevel(LogLevel.DEBUG);
filter.setSessionClosedLogLevel(LogLevel.DEBUG);
filter.setSessionCreatedLogLevel(LogLevel.DEBUG);
filter.setSessionIdleLogLevel(LogLevel.DEBUG);
filter.setSessionOpenedLogLevel(LogLevel.DEBUG);
acceptor.getFilterChain().addLast("logger", filter);
acceptor.setReuseAddress(true);//设置的是主服务监听的端口可以重用
acceptor.getSessionConfig().setReuseAddress(true);//设置每一个非主监听连接的端口可以重用
MINA2中,当启动一个服务端的时候,要设定初始化缓冲区的长度,如果不设置这个值,系统默认为2048,当客户端发过来的消息超过设定值的时候,MINA2的机制是分段接受的,将字符是放入缓冲区中读取,所以在读取消息的时候,需要判断有多少次。这样的好处就是可以节省通讯的流量。
acceptor.getSessionConfig().setReceiveBufferSize(1024);//设置输入缓冲区的大小
acceptor.getSessionConfig().setSendBufferSize(10240);//设置输出缓冲区的大小
//设置为非延迟发送,为true则不组装成大包发送,收到东西马上发出
acceptor.getSessionConfig().setTcpNoDelay(true);
//设置主服务监听端口的监听队列的最大值为100,如果当前已经有100个连接,再新的连接来将被服务器拒绝
acceptor.setBacklog(100);
acceptor.setDefaultLocalAddress(new
InetSocketAddress(port));
//加入处理器(Handler)到Acceptor
acceptor.setHandler(new YourHandler());
acceptor.bind();
}
二、 初始化客户端
客户端的初始化和服务器端其实是一样的,就是初始化类不一样,客户端是作为发送者的
SocketConnector connector = new NioSocketConnector();
connector.getFilterChain().addLast(
"codec",
new ProtocolCodecFilter(new
XmlCodecFactory(Charset
1. .forName(charsetName), null, sertType))); //指定线程池
connector.getFilterChain().addLast("executor", new 、、ExecutorFilter());
//指定业务处理类
connector.setHandler(this);
三、 处理流程
NioSocketAcceptor是MINA的适配器,一切都是从这里开始的。MINA中有个过滤器和处理器的概念,过滤器用来过滤数据,处理器用来处理数据。具体来说MINA的处理模型就是request->过滤器A->过滤器B->处理器->过滤器B->过滤器A->response,这里的request和response类似serlvet的request和response。
acceptor.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new WebDecoder(),new
XmlEncoder()));
//request->WebDecoder->XmlHander->WebEncode->response
acceptor.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new WebDecoder(),new XmlEncoder()));
//这里是处理逻辑的关键部位,请求的处理都是在WebDecoder类和XmlEncoder类中处理,可以明显从命名上看出来一个是用来解码,另一个是用来编码,requet过来后先进入WebDecoder类(实现了ProtocolDecoder接口)进行解码处理,这里可以加入自己的逻辑把传进来的流解码成自己需要的信息。而XmlEncoder类(实现了ProtocolEncoder接口)是进行编码,在这个类里面加入自己的逻辑把处理后的信息组装发送给客户端(response)。而在解码和编码过程中XmlHander(扩展了IoHandlerAdapter抽象类)起到了处理器的作用。
现在详细描述一下request->WebDecoder->XmlHander->WebEncode->response的过程:客户端发送一个请求到MINA服务器,这里相当于来了一个requet。请求首先来到WebDecoder类(实现了ProtocolDecoder接口)中的
boolean decode(IoSession session, IoBuffer in, ProtocolDecoderOutput
out) throws Exception{}方法
/*
参数in:用户请求信息全存在这里,读数据就从in这里读。
参数out:用来输出处理后的数据到Filter的下一个过滤器,如果没有过滤器了就输出到XmlHander,这里有点和 servelt的过滤器类似。利用out.write(Object object);这个函数可以把数据传到下一个Filter。我们可以自己定义 一个对象,我们假设为Request,用它来传递消息,那末这里就可以写成out.write(new
RequsetMessage()); 如果这个方法返回false,就是说当前逻辑包还没接收完(也就是当前的IoBuffer并没有包含足够的数据),需要再次 执行decode方法(再次获取新的IoBuffer),用来获取足够的数据。如果返回值为true就表示可以不执行decode方 法了,但是要激活handler方法,必须要调用out.write方法。
public class RequestMessage{}//这里什么也不做
*/
*/
然后到XmlHander(扩展了IoHandlerAdapter抽象类)中的
void messageReceived(IoSession session, Object message) throws
Exception{}方法
WriteFuture future = session.write(response);//session中必须加入这个代码,才会激活encode方法
future.addListener(IoFutureListener.CLOSE);//这个的作用是发送完毕后关闭连接,加了就是短连接,不然是长连接 ;
在XmlHanler类中可以在重载sessionIdle方法,这个方法判断整个SOCKET连接通道是否空闲,可以再这里间隔(在服务店启动的时候设置idleTime)发送心跳包来保持各个长连接:
/**
*当网络通道空闲时此方法被调用,在这里可以判断是读空闲、写空闲还是两个都空闲,以便做出正确的处理
一般的网络通讯程序都要与服务器端保持长连接,所以这里可以发一下网络测试数据以保持与服务器端的连接
* @param session 会话信息
* @param status 状态
* @throws Exception 异常
*/
@Override
public void sessionIdle(IoSession session, IdleStatus status)
throws Exception
IoFutureListener里面有个operationComplete(IoFuture future)方法,当流发送完成之后才调用这个方法。
/*
参数message:用来获取Filter传递过来的对象.对应代码RequestMessage
request = (RequestMessage) message;