Apache MINA简单介绍及其使用
1、简单介绍
首先,Mina是个什么东西?看下官方网站(http://mina.apache.org/)对它的解释:Apache的Mina(Multipurpose Infrastructure Networked Applications)是一个网络应用框架,可以帮助用户开发高性能和高扩展性的网络应用程序;它提供了一个抽象的、事件驱动的异步API,使Java NIO在各种传输协议(如TCP/IP,UDP/IP协议等)下快速高效开发。
Apache Mina也称为:
- NIO框架
- 客户端/服务端框架(典型的C/S架构)
- 网络套接字(networking socket)类库
- 事件驱动的异步API(注意:在JDK7中也新增了异步API)
总之:我们简单理解它是一个封装底层IO操作,提供高级操作API的通讯框架!
2、基本框架
Mina的通信流程大致如上图所示,各个组件功能有:
(1) IoService:这个接口在一个线程上负责套接字的建立,拥有自己的Selector,监
听是否有连接被建立。
(Mina底层使用Java NIO, 因此它是典型的使用Reactor模式架构的,采用事件驱动编程 , Mina运行用户自定义线程模型,可以是单线程、多线程、线程池等 ,
跟JAVA Socket不一样, Mina是非阻塞的Socket,它内部已经保证了对各个连接(session)的业务和数据的隔离,采用轮询机制为各个session分配CPU资源,
所以,你就不需要再去考虑不同Socket连接需要用不同的线程去操纵的问题了。)
(2) IoProcessor:这个接口在另一个线程上负责检查是否有数据在通道上读写,也就是
说它也拥有自己的Selector,这是与我们使用JAVA NIO 编码时的一个不同之处,
通常在JAVA NIO 编码中,我们都是使用一个Selector,也就是不区分IoService
与 IoProcessor 两个功能接口。另外,IoProcessor 负责调用注册在IoService 上
的过滤器,并在过滤器链之后调用IoHandler。
(3) IoFilter:这个接口定义一组拦截器,这些拦截器可以包括日志输出、黑名单过滤、
数据的编码(write 方向)与解码(read 方向)等功能,其中数据的encode 与 decode
是最为重要的、也是你在使用Mina 时最主要关注的地方。
(4) IoHandler:这个接口负责编写业务逻辑,也就是接收、发送数据的地方。
3、MINA示例实现
1、依赖包
- log4j.jar
- mina-core-2.0.4.jar
- slf4j-api-1.6.3.jar
- slf4j-log4j12-1.6.3.jar
2、示例代码
MinaTimeServer.java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
/**
*/
public class MinaTimeServer {
// 服务器监听端口
private static final int PORT = 8888;
/**
*
*/
public MinaTimeServer() {
// TODO Auto-generated constructor stub
}
/**
* @param args
*/
public static void main(String[] args) {
// 服务器端的主要对象
IoAcceptor acceptor = new NioSocketAcceptor();
// 设置Filter链
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
// 协议解析,采用mina现成的UTF-8字符串处理方式
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
// 设置消息处理类(创建、关闭Session,可读可写等等,继承自接口IoHandler)
acceptor.setHandler(new TimeServerHandler() );
// 设置接收缓存区大小
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
try {
// 服务器开始监听
acceptor.bind( new InetSocketAddress(PORT) );
}catch(Exception e){
e.printStackTrace();
}
}
}
TimeServerHandler.java
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import java.util.Date;
/**
* 服务器端业务逻辑
*/
/**
* 继承自IoHandlerAdapter,IoHandlerAdapter继承接口 IoHandler
类IoHandlerAdapter实现了IoHandler的所有方法,只要重载关心的几个方法就可以了
*/
public class TimeServerHandler extends IoHandlerAdapter {
@Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
cause.printStackTrace();
}
/*
* 这个方法是目前这个类里最主要的,
* 当接收到消息,只要不是quit,就把服务器当前的时间返回给客户端
* 如果是quit,则关闭客户端连接*/
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
String str = message.toString();
if (str.trim().equalsIgnoreCase("quit")) {
session.close();
return;
}
Date date = new Date();
System.out.println("hello"+str+session.getRemoteAddress()+date.toString());
session.write("i am recived");
System.out.println("Message written...");
}
@Override
public void sessionClosed(IoSession session) throws Exception {
// TODO Auto-generated method stub
super.sessionClosed(session);
System.out.println("客户端与服务端断开连接.....");
}
}
MinaTimeClient.java
import java.net.InetSocketAddress;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
/**
* mina客户端
*/
public class MinaTimeClient {
public static void main(String []args)throws Exception{
//Create TCP/IP connection
NioSocketConnector connector = new NioSocketConnector();
//创建接受数据的过滤器
DefaultIoFilterChainBuilder chain = connector.getFilterChain();
//设定这个过滤器将一行一行(/r/n)的读取数据
chain.addLast("myChin", new ProtocolCodecFilter(new TextLineCodecFactory()));
//客户端的消息处理器:一个SamplMinaServerHander对象
connector.setHandler(new TimeClientHandler());
//set connect timeout
connector.setConnectTimeout(30);
//连接到服务器:
ConnectFuture cf = connector.connect(new InetSocketAddress("localhost",8888));
//Wait for the connection attempt to be finished.
cf.awaitUninterruptibly();
cf.getSession().getCloseFuture().awaitUninterruptibly();
connector.dispose();
}
}
TimeClientHandler.java
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
/**
* 客户端业务处理逻辑
*/
public class TimeClientHandler extends IoHandlerAdapter {
// 当客户端连接进入时
@Override
public void sessionOpened(IoSession session) throws Exception {
System.out.println("incomming 客户端: " + session.getRemoteAddress());
session.write("i am coming");
}
@Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
System.out.println("客户端发送信息异常....");
}
// 当客户端发送消息到达时
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
System.out.println("服务器返回的数据:" + message.toString());
}
@Override
public void sessionClosed(IoSession session) throws Exception {
System.out.println("客户端与服务端断开连接.....");
}
@Override
public void sessionCreated(IoSession session) throws Exception {
// TODO Auto-generated method stub
System.out
.println("one Client Connection" + session.getRemoteAddress());
session.write("我来了······");
}
}
4、常见错误
- 错误
- 解决方法
这个错误是jar包版本太低导致的,因此只需下载高版本的jar包并替换。
5、参考文献
【1】http://www.cnblogs.com/xuekyo/archive/2013/03/06/2945826.html
【2】http://blog.csdn.net/madun/article/details/7890885
【3】http://blog.csdn.net/lsh6688/article/details/9671281