MINA学习之体系介绍
基于MINA应用程序结构图:
我们可以看出,MINA是应用程序(客户端或服务端)和底层基于TCP,UDP等通讯协议的网络层之间的粘合剂。而且各个模块之间是相互独立的,你只需要在MINA体
系基础上设计你的应用程序,而不用去处理复杂的网络层。
下图展示了MINA的内部组件以及MINA各个组件的功能。
很显然,基于MINA的应用程序被划分为3层:
1. I/O Service -- 执行真正的I/O操作
2. I/O Filter Chain -- 过滤,转换字节流为想要的数据结构
3. I/O Handler -- 实现顶层业务逻辑
因此,想要创建基于MINA的应用程序,须完成以下操作:
1. 创建 I/O Service --从已有可用的Service(*Acceptor) 或创建你定义的
2. 创建Filter Chain -- 从已有可有的Filter中选择或者创建自定义的Filter
3. 创建I/O Handler -- 写业务逻辑来处理不同的消息
MINA服务端体系
MINA服务端处理流程:
1. IOAcceptor 侦听网络上的链接和包
2. 针对每一个链接,一个新的session将会被创建,并且随后该 Ip+ 端口上的请求都会被这个session处理
3. 所有的包从Session处接受后,传送给Filter,Filters 用于修改包内容(如将字节流转换成特定的java bean,增加或删除信息等等),将字节流和java bean业务对象之
相互转换常常会用到PacketEncoder / Decoder两个类
4. 最后,转换后的包或对象将由IOHandler来处理
Session 创建:
只要有客户端连接到MINA服务端,都会为该链接创建一个Sessiion并在Session存放一些数据。
传入的消息处理:
假设一个Session已经被创建,任何传入的消息都将会导致Selector唤醒。
MINA 客户端体系
Simple Tcp Server
import java.util.Date; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IoSession; public class TimeServerHandler extends IoHandlerAdapter { @Override public void exceptionCaught( IoSession session, Throwable cause ) throws Exception { cause.printStackTrace(); } @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(); session.write( date.toString() ); System.out.println("Message written..."); } @Override public void sessionIdle( IoSession session, IdleStatus status ) throws Exception { System.out.println( "IDLE " + session.getIdleCount( status )); } }2. 启动服务端
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 = 9123; public static void main( String[] args ) throws IOException { IoAcceptor acceptor = new NioSocketAcceptor(); acceptor.getFilterChain().addLast( "logger", new LoggingFilter() ); acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" )))); acceptor.setHandler( new TimeServerHandler() ); acceptor.getSessionConfig().setReadBufferSize( 2048 ); acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 ); acceptor.bind( new InetSocketAddress(PORT) ); } }
Simple Tcp Clinent:
public static void main(String[] args) throws Throwable { NioSocketConnector connector = new NioSocketConnector(); connector.setConnectTimeoutMillis(CONNECT_TIMEOUT); if (USE_CUSTOM_CODEC) { connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new SumUpProtocolCodecFactory(false))); } else { connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); } connector.getFilterChain().addLast("logger", new LoggingFilter()); connector.setHandler(new ClientSessionHandler(values)); IoSession session; for (;;) { try { ConnectFuture future = connector.connect(new InetSocketAddress(HOSTNAME, PORT)); future.awaitUninterruptibly(); session = future.getSession(); break; } catch (RuntimeIoException e) { System.err.println("Failed to connect."); e.printStackTrace(); Thread.sleep(5000); } } // wait until the summation is done session.getCloseFuture().awaitUninterruptibly(); connector.dispose(); }