zoukankan      html  css  js  c++  java
  • Socket网络框架 MINA

    引用:http://apps.hi.baidu.com/share/detail/31519395

    http://apps.hi.baidu.com/share/user/65276d79647265616d5f7869616f3608

    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。

    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();


    采用MINA进行socket开发,一般步骤如下:
    1:
    server:
    IoAcceptor acceptor = new SocketAcceptor(); //建立client接收器
    or client:
    SocketConnector connector = new SocketConnector();  //建立一个连接器
    2:server的属性配置:
    SocketAcceptorConfig cfg = new SocketAcceptorConfig();
    cfg.setReuseAddress(true);
    cfg.getFilterChain().addLast(
    "codec",
    new ProtocolCodecFilter( new ObjectSerializationCodecFactory() ) ); //对象序列化 codec factory
    cfg.getFilterChain().addLast( "logger", new LoggingFilter() );
    3:绑定 address和business logic
    server:
    acceptor.bind(
    new InetSocketAddress( SERVER_PORT ),
    new ServerSessionHandler( ), cfg ); // 绑定address和handler

    client:
    connector.connect(new InetSocketAddress( HOSTNAME, PORT ),
    new ClientSessionHandler(msg), cfg );

    下面的这个简单的example演示client和server传递object的过程:
    Message.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
    public class Client
    {
    private static final String HOSTNAME = "localhost";
    private static final int PORT = 8080;
    private static final int CONNECT_TIMEOUT = 30; // seconds


    public static void main( String[] args ) throws Throwable
    {
    SocketConnector connector = new SocketConnector();        
    // Configure the service.
    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
    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
    public class Server
    {
    private static final int SERVER_PORT = 8080;

        public static void main( String[] args ) throws Throwable
    {
    IoAcceptor acceptor = new SocketAcceptor();

    // Prepare the service configuration.
     
    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
    public class ServerSessionHandler extends IoHandlerAdapter
    {
    public void sessionOpened( IoSession session )
    {
    // set idle time to 60 seconds
    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);
    // communicate 30 times,then close the session.
    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." );
    // disconnect an idle client
    session.close();
    }

        public void exceptionCaught( IoSession session, Throwable cause )
    {
    // close the connection on exceptional situation
    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

  • 相关阅读:
    OpenFire源码学习之十九:在openfire中使用redis插件(上)
    OpenFire源码学习之十八:IOS离线推送
    OpenFire源码学习之十七:HTTP Service插件
    OpenFire源码学习之十六:wildfire
    OpenFire源码学习之十五:插件开发
    OpenFire源码学习之十四:插件管理
    OpenFire源码学习之十三:消息处理
    数据挖掘入门
    iOS小技巧
    图片加载完成之前对图片高度侦测
  • 原文地址:https://www.cnblogs.com/sode/p/2346881.html
Copyright © 2011-2022 走看看