nio socket 及其开源框架MINA学习总结(二)

来源:互联网 发布:蝶々世界动作数据 编辑:程序博客网 时间:2024/04/30 07:47

3:Socket网络框架 MINA
MINA是一个网络应用框架,在不牺牲性能和可扩展性的前提下用于解决如下问题:
1:快速开发自己的英勇。
2:高可维护性,高可复用性:网络I/O编码,消息的编/解码,业务逻辑互相分离。
3:相对容易的进行单元测试。

3.1 IoFilters:
IoFilter为MINA的功能扩展提供了接口。它拦截所有的IO事件进行事件的预处理和后处理(AOP)。我们可以把它想象成
Servlet的filters。
IoFilter能够实现以下几种目的:
事件日志
性能检测
数据转换(e.g. SSL support),codec
防火墙…等等

3.2 codec: ProtocolCodecFactory
MINA提供了方便的Protocol支持。如上说讲,codec在IoFilters中设置。
通过它的Encoder和Decoder,可以方便的扩展并支持各种基于Socket的网络协议,比如HTTP服务器、FTP服务器、Telnet服务器等等。

要实现自己的编码/解码器(codec)只需要实现interface: ProtocolCodecFactory即可.
MINA 1.0版本,MINA已经实现了几个常用的(codec factory):

DemuxingProtocolCodecFactory,
NettyCodecFactory,
ObjectSerializationCodecFactory,
TextLineCodecFactory
 
其中:
TextLineCodecFactory:
 A ProtocolCodecFactory that performs encoding and decoding between a text line data and a Java
 string object. This codec is useful especially when you work with a text-based protocols such as SMTP and IMAP.

ObjectSerializationCodecFactory:
A ProtocolCodecFactory that serializes and deserializes Java objects. This codec is very useful when
you have to prototype your application rapidly without any specific codec.

DemuxingProtocolCodecFactory:
A composite ProtocolCodecFactory that consists of multiple MessageEncoders and MessageDecoders. ProtocolEncoder
and ProtocolDecoder this factory returns demultiplex incoming messages and buffers to appropriate MessageEncoders
and MessageDecoders.

NettyCodecFactory:
A MINA ProtocolCodecFactory that provides encoder and decoder for Netty2 Messages and MessageRecognizers.

3.3 business logic: IoHandler

MINA中,所有的业务逻辑都有实现了IoHandler的class完成
interfaceHandles:
 all protocol events fired by MINA. There are 6 event handler methods, and they are all invoked by MINA automatically.
 当事件发生时,将触发IoHandler中的方法:
 sessionCreated(),
sessionOpened(),
sessionClosed(),
sessionIdle(),
exceptionCaught(),
messageReceived(),
messageSent()


MINA 1.O中,IoHandler的实现类:
ChainedIoHandler,
DemuxingIoHandler,
IoHandlerAdapter,
SingleSessionIoHandlerDelegate,
StreamIoHandler

具体细节可参考javadoc。

3.4   MINA的高级主题:线程模式
MINA通过它灵活的filter机制来提供多种线程模型。
没有线程池过滤器被使用时MINA运行在一个单线程模式。
如果添加了一个IoThreadPoolFilter到IoAcceptor,将得到一个leader-follower模式的线程池。
如果再添加一个ProtocolThreadPoolFilter,server将有两个线程池;
一个(IoThreadPoolFilter)被用于对message对象进行转换,另外一个(ProtocolThreadPoolFilter)被用于处理业务逻辑。
SimpleServiceRegistry加上IoThreadPoolFilter和ProtocolThreadPoolFilter的缺省实现即可适用于需
要高伸缩性的应用。如果想使用自己的线程模型,请参考SimpleServiceRegistry的源代码,并且自己

初始化Acceptor。

java 代码

 

  1. IoThreadPoolFilter threadPool = new IoThreadPoolFilter();threadPool.start();   
  2. IoAcceptor acceptor = new SocketAcceptor();   
  3. acceptor.getFilterChain().addLast( "threadPool", threadPool);   
  4. ProtocolThreadPoolFilter threadPool2 = new ProtocolThreadPoolFilter();   
  5. threadPool2.start();   
  6. ProtocolAcceptor acceptor2 = new IoProtocolAcceptor( acceptor );   
  7. acceptor2.getFilterChain().addLast( "threadPool", threadPool2 );   
  8. ...   
  9. threadPool2.stop();   
  10. threadPool.stop();  


3.5 采用MINA进行socket开发,一般步骤如下:
1:

  1. IoAcceptor acceptor = new SocketAcceptor(); //建立client接收器   
  2. or client:   
  3. SocketConnector connector = new SocketConnector();  //建立一个连接器  


2:server的属性配置:

java 代码
  1. SocketAcceptorConfig cfg = new SocketAcceptorConfig();   
  2. cfg.setReuseAddress(true);   
  3. cfg.getFilterChain().addLast(   
  4.             "codec",   
  5.             new ProtocolCodecFilter( new ObjectSerializationCodecFactory() ) ); //对象序列化 codec factory   
  6. cfg.getFilterChain().addLast( "logger"new LoggingFilter() );  


3:绑定address和business logic
server:

java 代码
  1. acceptor.bind(   
  2.         new InetSocketAddress( SERVER_PORT ),   
  3.         new ServerSessionHandler( ), cfg ); // 绑定address和handler   
  4.   
  5.   
  6. connector.connect(new InetSocketAddress( HOSTNAME, PORT ),   
  7.                 new ClientSessionHandler(msg), cfg );   

下面的这个简单的example演示client和server传递object的过程:
Message.java

java 代码
  1. public class Message implements Serializable {   
  2.   
  3.     private int type;   
  4.     private int status;   
  5.     private String msgBody;   
  6.        
  7.     public Message(int type, int status, String msgBody)   
  8.     {   
  9.         this.type = type;   
  10.         this.status = status;   
  11.         this.msgBody = msgBody;   
  12.     }   
  13.   
  14.     public String getMsgBody() {   
  15.         return msgBody;   
  16.     }   
  17.   
  18.     public void setMsgBody(String msgBody) {   
  19.         this.msgBody = msgBody;   
  20.     }   
  21.   
  22.     public int getStatus() {   
  23.         return status;   
  24.     }   
  25.   
  26.     public void setStatus(int status) {   
  27.         this.status = status;   
  28.     }   
  29.   
  30.     public int getType() {   
  31.         return type;   
  32.     }   
  33.   
  34.     public void setType(int type) {   
  35.         this.type = type;   
  36.     }   
  37. }   
  38.   


Client.java

java 代码
  1. public class Client   
  2. {   
  3.     private static final String HOSTNAME = "localhost";   
  4.     private static final int PORT = 8080;   
  5.     private static final int CONNECT_TIMEOUT = 30// seconds   
  6.   
  7.   
  8.     public static void main( String[] args ) throws Throwable   
  9.     {   
  10.         SocketConnector connector = new SocketConnector();           
  11.         // Configure the service.   
  12.         SocketConnectorConfig cfg = new SocketConnectorConfig();   
  13.         cfg.setConnectTimeout( CONNECT_TIMEOUT );   
  14.           cfg.getFilterChain().addLast(   
  15.                     "codec",   
  16.                     new ProtocolCodecFilter( new ObjectSerializationCodecFactory() ) );   
  17.   
  18.         cfg.getFilterChain().addLast( "logger"new LoggingFilter() );   
  19.            
  20.         IoSession session;   
  21.         Message msg = new Message(0,1,"hello");   
  22.         connector.connect(new InetSocketAddress( HOSTNAME, PORT ),   
  23.                         new ClientSessionHandler(msg), cfg );   
  24.   
  25.     }   
  26. }   

ClientSessionHandler.java

java 代码
  1. public class ClientSessionHandler extends IoHandlerAdapter   
  2. {   
  3.     private Object msg;   
  4.        
  5.     public ClientSessionHandler(Object msg)   
  6.     {   
  7.         this.msg = msg;   
  8.     }   
  9.   
  10.   
  11.     public void sessionOpened( IoSession session )   
  12.     {   
  13.         session.write(this.msg);   
  14.     }   
  15.   
  16.     public void messageReceived( IoSession session, Object message )   
  17.     {   
  18.         System.out.println("in messageReceived!");   
  19.         Message rm = (Message ) message;           
  20.         SessionLog.debug(session, rm.getMsgBody());   
  21.         System.out.println("message is: " + rm.getMsgBody());   
  22.         session.write(rm);   
  23.     }   
  24.   
  25.     public void exceptionCaught( IoSession session, Throwable cause )   
  26.     {   
  27.         session.close();   
  28.     }   
  29. }   
  30.   


Server.java

java 代码
  1. public class Server   
  2. {   
  3.     private static final int SERVER_PORT = 8080;   
  4.   
  5.     public static void main( String[] args ) throws Throwable   
  6.     {   
  7.         IoAcceptor acceptor = new SocketAcceptor();   
  8.            
  9.         // Prepare the service configuration.   
  10.         SocketAcceptorConfig cfg = new SocketAcceptorConfig();   
  11.         cfg.setReuseAddress( true );   
  12.   
  13.         cfg.getFilterChain().addLast(   
  14.                     "codec",   
  15.                     new ProtocolCodecFilter( new ObjectSerializationCodecFactory() ) );   
  16.         cfg.getFilterChain().addLast( "logger"new LoggingFilter() );   
  17.   
  18.         acceptor.bind(   
  19.                 new InetSocketAddress( SERVER_PORT ),   
  20.                 new ServerSessionHandler( ), cfg );   
  21.   
  22.         System.out.println( "The server Listening on port " + SERVER_PORT );   
  23.     }   
  24. }  


ServerSessionHandler.java

java 代码
  1. public class ServerSessionHandler extends IoHandlerAdapter   
  2. {   
  3.     public void sessionOpened( IoSession session )   
  4.     {   
  5.         // set idle time to 60 seconds   
  6.         session.setIdleTime( IdleStatus.BOTH_IDLE, 60 );   
  7.         session.setAttribute("times",new Integer(0));   
  8.     }   
  9.   
  10.     public void messageReceived( IoSession session, Object message )   
  11.     {   
  12.         System.out.println("in messageReceived");   
  13.         int times = ((Integer)(session.getAttribute("times"))).intValue();   
  14.         System.out.println("tiems = " + times);   
  15.         // communicate 30 times,then close the session.   
  16.         if (times < 30)   
  17.         {   
  18.             times++;   
  19.             session.setAttribute("times"new Integer(times));              
  20.          Message msg;   
  21.          msg = (Message) message;   
  22.          msg.setMsgBody("in server side: " + msg.getMsgBody());    
  23.          System.out.println("begin send msg: " + msg.getMsgBody());   
  24.          session.write(msg);   
  25.         }   
  26.         else  
  27.         {   
  28.             session.close();   
  29.         }   
  30.     }   
  31.   
  32.     public void sessionIdle( IoSession session, IdleStatus status )   
  33.     {   
  34.         SessionLog.info( session, "Disconnecting the idle." );   
  35.         // disconnect an idle client   
  36.         session.close();   
  37.     }   
  38.   
  39.     public void exceptionCaught( IoSession session, Throwable cause )   
  40.     {   
  41.         // close the connection on exceptional situation   
  42.         session.close();   
  43.     }   
  44. }   
  45.   


MINA自己附带的Demo已经很好的说明了它的运用。
值得一提的是它的SumUp:客户端发送几个数字,服务端求和后并返回结果。这个简单的程序演示了如何自己实现CODEC。

补充提示:
下载并运行MINA的demo程序还颇非周折:
运行MINA demo appli擦tion:
1:在JDK5
产生错误:
Exception in thread "main" java.lang.NoClassDefFoundError: edu/emory/mathcs/backport/java/util/concurrent/Executor
 at org.apache.mina.example.reverser.Main.main(Main.java:44)
 
察看mina的QA email:
 http://www.mail-archive.com/mina-dev@directory.apache.org/msg02252.html

原来需要下载:backport-util-concurrent.jar并加入classpath
http://dcl.mathcs.emory.edu/util/backport-util-concurrent

继续运行还是报错:
Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory

原来MINA采用了slf4j项目作为log,继续下载
slf4j-simple.jar等,并加入classpath:
http://www.slf4j.org/download.html

附件是mina demo的eclipse工程。导入就可运行,所有的相关jar包在bin目录下