mina2.0 源码分析--- 基于nio的服务端socket监听过程

该博客详细分析了MINA2.0服务端如何利用NIO进行单线程轮询机制的Socket监听。从创建Selector、ServerSocketChannel到启动Acceptor,解释了MINA的IoAcceptor、SimpleIoProcessorPool的工作原理,以及Acceptor线程如何处理客户端请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

整体来说 ,mina服务端采用基于nio的单线程,轮询机制。 使用selector  获取客户端的链接,并创建sesssion,session通过process来处理io操作。

    nio的典型模式如下所示:

 

Java代码
  1. private  NioEchoServer() throws  IOException {  
  2.        Selector  roller = Selector.open();  
  3.         ServerSocketChannel serverChannel = ServerSocketChannel.open();  //   
  4.         serverChannel.socket().bind(new  InetSocketAddress(port));  
  5.         serverChannel.configureBlocking(false );  
  6.         serverChannel.register(roller, SelectionKey.OP_ACCEPT);  
  7.     }  
  8.   
  9.   
  10.   public  void  start() throws  IOException {  
  11.         int  keyAdded = 0 ;  
  12.         while  ((keyAdded = roller.select()) > 0 ) {  
  13.             Set<SelectionKey> keySets = roller.selectedKeys();  
  14.             Iterator iter = keySets.iterator();  
  15.             while  (iter.hasNext()) {  
  16.                 SelectionKey key = (SelectionKey) iter.next();  
  17.                 iter.remove();  
  18.                 actionHandler(key);  
  19.             }  
  20.         }  
  21.     }  
private NioEchoServer() throws IOException {
       Selector  roller = Selector.open();
        ServerSocketChannel serverChannel = ServerSocketChannel.open();  //
        serverChannel.socket().bind(new InetSocketAddress(port));
        serverChannel.configureBlocking(false);
        serverChannel.register(roller, SelectionKey.OP_ACCEPT);
    }


  public void start() throws IOException {
        int keyAdded = 0;
        while ((keyAdded = roller.select()) > 0) {
            Set<SelectionKey> keySets = roller.selectedKeys();
            Iterator iter = keySets.iterator();
            while (iter.hasNext()) {
                SelectionKey key = (SelectionKey) iter.next();
                iter.remove();
                actionHandler(key);
            }
        }
    }

   1 服务端绑定port

   2 创建Selector

   3 创建SeversocketChannel,面向流的侦听socket 通道。

   4  监听客户端的请求,

 

 

 

接下来就通过mina 创建服务端socket Accpeptor 使用单线程并监处理端口和客户端请求,学习一下mina的源码

Java代码
  1. IoAcceptor  acceptor  =  new   NioSoketAcceptor ();  //根据实现的类,调用不同的构造方法   
IoAcceptor  acceptor  =  new  NioSoketAcceptor ();  //根据实现的类,调用不同的构造方法

 

上面代码, 创建一个socket Acceptor  ,mina内部实现如下 :

 

super(new DefaultSocketSessionConfig(), NioProcessor.class); //传入具体的ioprocess 的实现类。

 

最终调用的类和构造方法:

Java代码
  1. AbstractPollingIoAcceptor       
  2.    protected  AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,    //模板模式的使用,根据子类传入IoProcessor实现类构造SimpleIoprocessorPool 池   
  3.             Class<? extends  IoProcessor<T>> processorClass) {  
  4.         this (sessionConfig, nullnew  SimpleIoProcessorPool<T>(processorClass),  
  5.                 true );  
  6.     }  
AbstractPollingIoAcceptor     
   protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,    //模板模式的使用,根据子类传入IoProcessor实现类构造SimpleIoprocessorPool 池
            Class<? extends IoProcessor<T>> processorClass) {
        this(sessionConfig, null, new SimpleIoProcessorPool<T>(processorClass),
                true);
    }

 


  SimpleIoProcessorPool 创建线程池,提供给Iosession ,做具体的io处理工作。

Java代码
  1. public  SimpleIoProcessorPool(Class<? extends  IoProcessor<T>> processorType) {  
  2.   
  3.         this (processorType, null , DEFAULT_SIZE);  
  4.   
  5.    }  
  6.      public  SimpleIoProcessorPool(Class<? extends  IoProcessor<T>> processorType, Executor executor, int  size) { //构造IOprocessorPool 中的IOprocessor ,并指定Executor;   
  7.     try  {  
  8.           .....................  
  9.           .....................     
  10.          //创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们,并在需要时使用提供的 ThreadFactory 创建新线程   
  11.           this .executor = executor = Executors.newCachedThreadPool();   //return  new ThreadPoolExecutor ;   
  12.           ...............................  
  13.           for  (int  i = 0 ; i < pool.length; i ++)  
  14.                  .........................  
  15.                  ...........................  
  16.             //指定Executor .,线程池,提供构造线程。 使用构造函数 NioProcess(Executor execytor )构造processor ,打开selector 。        
  17.                       processor = processorType.getConstructor(ExecutorService.class ).newInstance(executor);  
  18.                 .............................  
  19.                 ..................................  
  20.                  pool[i] = processor;  
  21.                       .....................  
  22.                     } catch  (NoSuchMethodException e) {  
  23.      
public SimpleIoProcessorPool(Class<? extends IoProcessor<T>> processorType) {

        this(processorType, null, DEFAULT_SIZE);

   }
     public SimpleIoProcessorPool(Class<? extends IoProcessor<T>> processorType, Executor executor, int size) { //构造IOprocessorPool 中的IOprocessor ,并指定Executor;
    try {
          .....................
          .....................   
         //创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们,并在需要时使用提供的 ThreadFactory 创建新线程
          this.executor = executor = Executors.newCachedThreadPool();   //return  new ThreadPoolExecutor ;
          ...............................
          for (int i = 0; i < pool.length; i ++)
                 .........................
                 ...........................
            //指定Executor .,线程池,提供构造线程。 使用构造函数 NioProcess(Executor execytor )构造processor ,打开selector 。     
                      processor = processorType.getConstructor(ExecutorService.class).newInstance(executor);
                .............................
                ..................................
                 pool[i] = processor;
                      .....................
                    } catch (NoSuchMethodException e) {
   

 

       
   应用代码中 调用acceptor .bind(),完成对特定端口的绑定,开始监听。
    nioScoket bind ()  调用  AbstarctIoProcessor .bind() ,调用 AbstractPollingIo.bindInternal()

完成对客户端的监听。

Java代码
  1. public  final  void  bind(Iterable<? extends  SocketAddress> localAddresses) throws  IOException {  
  2.   {  
  3.       .......................  
  4.             .....................  
  5.       try  {  
  6.                 boundAddresses.addAll(bindInternal(localAddressesCopy));  //模板模式   
  7.             } catch  (IOException e) {  
  8.                 throw  e;  
  9.             } catch  (RuntimeException e) {  
  10.                 throw  e;  
  11.             } catch  (Throwable e) {  
  12.                 throw  new  RuntimeIoException(  
  13.                         "Failed to bind to: "  + getLocalAddresses(), e);  
  14.             }  
  15.         }  
  16.                   ...................  
  17.         ....................  
  18.   }  
  19.    
  20. AbstractPollingIoacceptor  :  
  21.   protected  final  Set<SocketAddress> bindInternal( List<? extends  SocketAddress> localAddresses) throws  Exception {  
  22.   
  23.         AcceptorOperationFuture request = new  AcceptorOperationFuture( localAddresses);  
  24.   
  25.        registerQueue.add(request);  
  26.   
  27.   
  28.     //   acceptor 是一个接受用户请求的线程。It's a thread accepting incoming connections from clients.   
  29.     //  executor.execute(new NamePreservingRunnable(acceptor, actualThreadName));   
  30.      //启动接受用户请求。   
  31.         startupAcceptor();              
  32.   
  33.         wakeup();      //selector.wakeup(); 使尚未返回的第一个选择操作立即返回。   
  34.   
  35.         request.awaitUninterruptibly();  ////堵塞直至监听成功    
  36.   
  37.         if  (request.getException() != null ) {  
  38.   
  39.              throw  request.getException();  
  40.         }  
  41.         Set<SocketAddress> newLocalAddresses = new  HashSet<SocketAddress>();  
  42.           
  43.         for  (H handle:boundHandles.values()) {  
  44.             newLocalAddresses.add(localAddress(handle));     
  45.             return  newLocalAddresses;  
  46.   
  47.   }  
public final void bind(Iterable<? extends SocketAddress> localAddresses) throws IOException {
  {
      .......................
            .....................
      try {
                boundAddresses.addAll(bindInternal(localAddressesCopy));  //模板模式
            } catch (IOException e) {
                throw e;
            } catch (RuntimeException e) {
                throw e;
            } catch (Throwable e) {
                throw new RuntimeIoException(
                        "Failed to bind to: " + getLocalAddresses(), e);
            }
        }
                  ...................
        ....................
  }
 
AbstractPollingIoacceptor  :
  protected final Set<SocketAddress> bindInternal( List<? extends SocketAddress> localAddresses) throws Exception {

        AcceptorOperationFuture request = new AcceptorOperationFuture( localAddresses);

       registerQueue.add(request);


    //   acceptor 是一个接受用户请求的线程。It's a thread accepting incoming connections from clients.
    //  executor.execute(new NamePreservingRunnable(acceptor, actualThreadName));
     //启动接受用户请求。
        startupAcceptor();            

        wakeup();      //selector.wakeup(); 使尚未返回的第一个选择操作立即返回。

        request.awaitUninterruptibly();  ////堵塞直至监听成功 

        if (request.getException() != null) {

             throw request.getException();
        }
        Set<SocketAddress> newLocalAddresses = new HashSet<SocketAddress>();
        
        for (H handle:boundHandles.values()) {
            newLocalAddresses.add(localAddress(handle));   
            return newLocalAddresses;

  }

 

AbstractPollingIoAcceptor 的bindInternal   (。。。) 调用 startupAcceptor,执行 acceptor 线程 。

 

使用自己的私有类 ,private class Acceptor implements Runnable  ,来处理接收客户端请求工作

 

Java代码
  1. private  void  startupAcceptor() {  
  2.        // If the acceptor is not ready, clear the queues   
  3.        // TODO : they should already be clean : do we have to do that ?   
  4.        if  (!selectable) {  
  5.            registerQueue.clear();  
  6.            cancelQueue.clear();  
  7.        }  
  8.   
  9.        // start the acceptor if not already started   
  10.        synchronized  (lock) {  
  11.            if  (acceptor == null ) {  
  12.                acceptor = new  Acceptor();  
  13.                executeWorker(acceptor);  
  14.            }  
  15.        }  
  16.    }  
 private void startupAcceptor() {
        // If the acceptor is not ready, clear the queues
        // TODO : they should already be clean : do we have to do that ?
        if (!selectable) {
            registerQueue.clear();
            cancelQueue.clear();
        }

        // start the acceptor if not already started
        synchronized (lock) {
            if (acceptor == null) {
                acceptor = new Acceptor();
                executeWorker(acceptor);
            }
        }
    }

 

 

循环处理客户端请求。

acceptor  ,work线程代码

Java代码
  1. /**  
  2.      * This class is called by the startupAcceptor() method and is  
  3.      * placed into a NamePreservingRunnable class.  
  4.      * It's a thread accepting incoming connections from clients.  
  5.      * The loop is stopped when all the bound handlers are unbound.  
  6.      */   
  7.     private  class  Acceptor implements  Runnable {  
  8.         public  void  run() {  
  9.             int  nHandles = 0 ;  
  10.   
  11.             while  (selectable) {  
  12.                 try  {  
  13.                     // Detect if we have some keys ready to be processed   
  14.                     // The select() will be woke up if some new connection   
  15.                     // have occurred, or if the selector has been explicitly   
  16.                     // woke up   
  17.                     int  selected = select();  
  18.   
  19.                     // this actually sets the selector to OP_ACCEPT,   
  20.                     // and binds to the port on which this class will   
  21.                     // listen on   
  22.                     nHandles += registerHandles();  
  23.   
  24.                     if  (selected > 0 ) {  
  25.                         // We have some connection request, let's process    
  26.                         // them here.    
  27.                         processHandles(selectedHandles());  
  28.                     }  
  29.   
  30.                     // check to see if any cancellation request has been made.   
  31.                     nHandles -= unregisterHandles();  
  32.   
  33.                     // Now, if the number of registred handles is 0, we can   
  34.                     // quit the loop: we don't have any socket listening   
  35.                     // for incoming connection.   
  36.                     if  (nHandles == 0 ) {  
  37.                         synchronized  (lock) {  
  38.                             if  (registerQueue.isEmpty()  
  39.                                     && cancelQueue.isEmpty()) {  
  40.                                 acceptor = null ;  
  41.                                 break ;  
  42.                             }  
  43.                         }  
  44.                     }  
  45.                 } catch  (Throwable e) {  
  46.                     ExceptionMonitor.getInstance().exceptionCaught(e);  
  47.   
  48.                     try  {  
  49.                         Thread.sleep(1000 );  
  50.                     } catch  (InterruptedException e1) {  
  51.                         ExceptionMonitor.getInstance().exceptionCaught(e1);  
  52.                     }  
  53.                 }  
  54.             }  
  55.   
  56.             // Cleanup all the processors, and shutdown the acceptor.   
  57.             if  (selectable && isDisposing()) {  
  58.                 selectable = false ;  
  59.                 try  {  
  60.                     if  (createdProcessor) {  
  61.                         processor.dispose();  
  62.                     }  
  63.                 } finally  {  
  64.                     try  {  
  65.                         synchronized  (disposalLock) {  
  66.                             if  (isDisposing()) {  
  67.                                 destroy();  
  68.                             }  
  69.                         }  
  70.                     } catch  (Exception e) {  
  71.                         ExceptionMonitor.getInstance().exceptionCaught(e);  
  72.                     } finally  {  
  73.                         disposalFuture.setDone();  
  74.                     }  
  75.                 }  
  76.             }  
  77.         } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值