整体来说 ,mina服务端采用基于nio的单线程,轮询机制。 使用selector 获取客户端的链接,并创建sesssion,session通过process来处理io操作。
nio的典型模式如下所示:
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的源码
IoAcceptor acceptor = new NioSoketAcceptor (); //根据实现的类,调用不同的构造方法
上面代码, 创建一个socket Acceptor ,mina内部实现如下 :
super(new DefaultSocketSessionConfig(), NioProcessor.class); //传入具体的ioprocess 的实现类。
最终调用的类和构造方法:
AbstractPollingIoAcceptor protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig, //模板模式的使用,根据子类传入IoProcessor实现类构造SimpleIoprocessorPool 池 Class<? extends IoProcessor<T>> processorClass) { this(sessionConfig, null, new SimpleIoProcessorPool<T>(processorClass), true); }
SimpleIoProcessorPool 创建线程池,提供给Iosession ,做具体的io处理工作。
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()
完成对客户端的监听。
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 ,来处理接收客户端请求工作
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线程代码
/** * This class is called by the startupAcceptor() method and is * placed into a NamePreservingRunnable class. * It's a thread accepting incoming connections from clients. * The loop is stopped when all the bound handlers are unbound. */ private class Acceptor implements Runnable { public void run() { int nHandles = 0; while (selectable) { try { // Detect if we have some keys ready to be processed // The select() will be woke up if some new connection // have occurred, or if the selector has been explicitly // woke up int selected = select(); // this actually sets the selector to OP_ACCEPT, // and binds to the port on which this class will // listen on nHandles += registerHandles(); if (selected > 0) { // We have some connection request, let's process // them here. processHandles(selectedHandles()); } // check to see if any cancellation request has been made. nHandles -= unregisterHandles(); // Now, if the number of registred handles is 0, we can // quit the loop: we don't have any socket listening // for incoming connection. if (nHandles == 0) { synchronized (lock) { if (registerQueue.isEmpty() && cancelQueue.isEmpty()) { acceptor = null; break; } } } } catch (Throwable e) { ExceptionMonitor.getInstance().exceptionCaught(e); try { Thread.sleep(1000); } catch (InterruptedException e1) { ExceptionMonitor.getInstance().exceptionCaught(e1); } } } // Cleanup all the processors, and shutdown the acceptor. if (selectable && isDisposing()) { selectable = false; try { if (createdProcessor) { processor.dispose(); } } finally { try { synchronized (disposalLock) { if (isDisposing()) { destroy(); } } } catch (Exception e) { ExceptionMonitor.getInstance().exceptionCaught(e); } finally { disposalFuture.setDone(); } } } }