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 代码
- IoThreadPoolFilter threadPool = new IoThreadPoolFilter();threadPool.start();
- IoAcceptor acceptor = new SocketAcceptor();
- acceptor.getFilterChain().addLast( "threadPool", threadPool);
- ProtocolThreadPoolFilter threadPool2 = new ProtocolThreadPoolFilter();
- threadPool2.start();
- ProtocolAcceptor acceptor2 = new IoProtocolAcceptor( acceptor );
- acceptor2.getFilterChain().addLast( "threadPool", threadPool2 );
- ...
- threadPool2.stop();
- threadPool.stop();
3.5 采用MINA进行socket开发,一般步骤如下: 1:
- IoAcceptor acceptor = new SocketAcceptor();
- or client:
- SocketConnector connector = new SocketConnector();
2:server的属性配置:
java 代码
- SocketAcceptorConfig cfg = new SocketAcceptorConfig();
- cfg.setReuseAddress(true);
- cfg.getFilterChain().addLast(
- "codec",
- new ProtocolCodecFilter( new ObjectSerializationCodecFactory() ) );
- cfg.getFilterChain().addLast( "logger", new LoggingFilter() );
3:绑定address和business logic server:
java 代码
- acceptor.bind(
- new InetSocketAddress( SERVER_PORT ),
- new ServerSessionHandler( ), cfg );
-
-
- connector.connect(new InetSocketAddress( HOSTNAME, PORT ),
- new ClientSessionHandler(msg), cfg );
下面的这个简单的example演示client和server传递object的过程: Message.java
java 代码
- public class Message implements Serializable {
-
- private int type;
- private int status;
- private String msgBody;
-
- public Message(int type, int status, String msgBody)
- {
- this.type = type;
- this.status = status;
- this.msgBody = msgBody;
- }
-
- public String getMsgBody() {
- return msgBody;
- }
-
- public void setMsgBody(String msgBody) {
- this.msgBody = msgBody;
- }
-
- public int getStatus() {
- return status;
- }
-
- public void setStatus(int status) {
- this.status = status;
- }
-
- public int getType() {
- return type;
- }
-
- public void setType(int type) {
- this.type = type;
- }
- }
-
Client.java
java 代码
- public class Client
- {
- private static final String HOSTNAME = "localhost";
- private static final int PORT = 8080;
- private static final int CONNECT_TIMEOUT = 30;
-
-
- public static void main( String[] args ) throws Throwable
- {
- SocketConnector connector = new SocketConnector();
-
- SocketConnectorConfig cfg = new SocketConnectorConfig();
- cfg.setConnectTimeout( CONNECT_TIMEOUT );
- cfg.getFilterChain().addLast(
- "codec",
- new ProtocolCodecFilter( new ObjectSerializationCodecFactory() ) );
-
- cfg.getFilterChain().addLast( "logger", new LoggingFilter() );
-
- IoSession session;
- Message msg = new Message(0,1,"hello");
- connector.connect(new InetSocketAddress( HOSTNAME, PORT ),
- new ClientSessionHandler(msg), cfg );
-
- }
- }
ClientSessionHandler.java
java 代码
- public class ClientSessionHandler extends IoHandlerAdapter
- {
- private Object msg;
-
- public ClientSessionHandler(Object msg)
- {
- this.msg = msg;
- }
-
-
- public void sessionOpened( IoSession session )
- {
- session.write(this.msg);
- }
-
- public void messageReceived( IoSession session, Object message )
- {
- System.out.println("in messageReceived!");
- Message rm = (Message ) message;
- SessionLog.debug(session, rm.getMsgBody());
- System.out.println("message is: " + rm.getMsgBody());
- session.write(rm);
- }
-
- public void exceptionCaught( IoSession session, Throwable cause )
- {
- session.close();
- }
- }
-
Server.java
java 代码
- public class Server
- {
- private static final int SERVER_PORT = 8080;
-
- public static void main( String[] args ) throws Throwable
- {
- IoAcceptor acceptor = new SocketAcceptor();
-
-
- SocketAcceptorConfig cfg = new SocketAcceptorConfig();
- cfg.setReuseAddress( true );
-
- cfg.getFilterChain().addLast(
- "codec",
- new ProtocolCodecFilter( new ObjectSerializationCodecFactory() ) );
- cfg.getFilterChain().addLast( "logger", new LoggingFilter() );
-
- acceptor.bind(
- new InetSocketAddress( SERVER_PORT ),
- new ServerSessionHandler( ), cfg );
-
- System.out.println( "The server Listening on port " + SERVER_PORT );
- }
- }
ServerSessionHandler.java
java 代码
- public class ServerSessionHandler extends IoHandlerAdapter
- {
- public void sessionOpened( IoSession session )
- {
-
- session.setIdleTime( IdleStatus.BOTH_IDLE, 60 );
- session.setAttribute("times",new Integer(0));
- }
-
- public void messageReceived( IoSession session, Object message )
- {
- System.out.println("in messageReceived");
- int times = ((Integer)(session.getAttribute("times"))).intValue();
- System.out.println("tiems = " + times);
-
- if (times < 30)
- {
- times++;
- session.setAttribute("times", new Integer(times));
- Message msg;
- msg = (Message) message;
- msg.setMsgBody("in server side: " + msg.getMsgBody());
- System.out.println("begin send msg: " + msg.getMsgBody());
- session.write(msg);
- }
- else
- {
- session.close();
- }
- }
-
- public void sessionIdle( IoSession session, IdleStatus status )
- {
- SessionLog.info( session, "Disconnecting the idle." );
-
- session.close();
- }
-
- public void exceptionCaught( IoSession session, Throwable cause )
- {
-
- session.close();
- }
- }
-
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目录下
|