MINA源码分析2-I/O操作

分析I/O操作首先我们从NioSocketAcceptor.java这个类为入口进行一步一步的跟踪分析。

首先我们了解NioSocketAcceptor.java:

AbstractPollingIoAcceptor,AbstractIoAcceptor,AbstractIoService是它的基类。

在NioSocketAcceptor中我们先看下DefaultSocketSessionConfig类,DefaultSocketSessionConfig的基类示AbstractIoSessionConfig,

AbstractIoSessionConfig是一些基本参数的设置,如:数据的缓冲区大小 ,超时等:

private int minReadBufferSize = 64;
    private int readBufferSize = 2048;
    private int maxReadBufferSize = 65536;
    private int idleTimeForRead;
    private int idleTimeForWrite;
    private int idleTimeForBoth;
    private int writeTimeout = 60;
    private boolean useReadOperation;
    private int throughputCalculationInterval = 3;

    protected AbstractIoSessionConfig() {
        // Do nothing
    }

    /**
     * {@inheritDoc}
     */
    public final void setAll(IoSessionConfig config) {
        if (config == null) {
            throw new NullPointerException("config");
        }

        setReadBufferSize(config.getReadBufferSize());
        setMinReadBufferSize(config.getMinReadBufferSize());
        setMaxReadBufferSize(config.getMaxReadBufferSize());
        setIdleTime(IdleStatus.BOTH_IDLE, config.getIdleTime(IdleStatus.BOTH_IDLE));
        setIdleTime(IdleStatus.READER_IDLE, config.getIdleTime(IdleStatus.READER_IDLE));
        setIdleTime(IdleStatus.WRITER_IDLE, config.getIdleTime(IdleStatus.WRITER_IDLE));
        setWriteTimeout(config.getWriteTimeout());
        setUseReadOperation(config.isUseReadOperation());
        setThroughputCalculationInterval(config.getThroughputCalculationInterval());

        doSetAll(config);
    }

再回到NioSocketAcceptor的基类AbstractPollingIoAcceptor,AbstractPollingIoAcceptor将NIO底层选择器打开:

private AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,
            Executor executor, IoProcessor<T> processor,
            boolean createdProcessor) {
        super(sessionConfig, executor);

        if (processor == null) {
            throw new NullPointerException("processor");
        }

        this.processor = processor;
        this.createdProcessor = createdProcessor;

        try {
            // Initialize the selector
            init();
            
            // The selector is now ready, we can switch the
            // flag to true so that incoming connection can be accepted
            selectable = true;
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeIoException("Failed to initialize.", e);
        } finally {
            if (!selectable) {
                try {
                    destroy();
                } catch (Exception e) {
                    ExceptionMonitor.getInstance().exceptionCaught(e);
                }
            }
        }
    }

然后我们跟踪AbstractIoAcceptor类,我们查看它的bind(SocketAddress localAddress)

 /**
     * {@inheritDoc}
     */
    public final void bind(SocketAddress localAddress) throws IOException {
        if (localAddress == null) {
            throw new NullPointerException("localAddress");
        }
        
        List<SocketAddress> localAddresses = new ArrayList<SocketAddress>(1);
        localAddresses.add(localAddress);
        bind(localAddresses);
    }

 /**
     * {@inheritDoc}
     */
    public final void bind(Iterable<? extends SocketAddress> localAddresses) throws IOException {
        if (isDisposing()) {
            throw new IllegalStateException("Already disposed.");
        }
        
        if (localAddresses == null) {
            throw new NullPointerException("localAddresses");
        }
        
        List<SocketAddress> localAddressesCopy = new ArrayList<SocketAddress>();
        
        for (SocketAddress a: localAddresses) {
            checkAddressType(a);
            localAddressesCopy.add(a);
        }
        
        if (localAddressesCopy.isEmpty()) {
            throw new IllegalArgumentException("localAddresses is empty.");
        }
        
        boolean activate = false;
        synchronized (bindLock) {
            if (boundAddresses.isEmpty()) {
                activate = true;
            }

            if (getHandler() == null) {
                throw new IllegalStateException("handler is not set.");
            }
            
            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);
            }
        }
        
        if (activate) {
            getListeners().fireServiceActivated();
        }
    }

我们重点分析下bindInternal这个方法,他是I/O核心地方:

这里面有3个需要队列:

    //注册队列
    private final Queue<AcceptorOperationFuture> registerQueue =
        new ConcurrentLinkedQueue<AcceptorOperationFuture>();
    //取消注册队列
    private final Queue<AcceptorOperationFuture> cancelQueue =
        new ConcurrentLinkedQueue<AcceptorOperationFuture>();
    //本地地址到服务器socket的映射表
    private final Map<SocketAddress, H> boundHandles =
        Collections.synchronizedMap(new HashMap<SocketAddress, H>());


 /**
     * {@inheritDoc}
     */
    @Override
    protected final Set<SocketAddress> bindInternal(
            List<? extends SocketAddress> localAddresses) throws Exception {
        // Create a bind request as a Future operation. When the selector
        // have handled the registration, it will signal this future.
    	//注册请求
        AcceptorOperationFuture request = new AcceptorOperationFuture(localAddresses);

        // adds the Registration request to the queue for the Workers
        // to handle
        //加入注册队列中,等待Acceptor处理
        registerQueue.add(request);

        // creates the Acceptor instance and has the local
        // executor kick it off.
        startupAcceptor();
        
        // As we just started the acceptor, we have to unblock the select()
        // in order to process the bind request we just have added to the 
        // registerQueue.
        //中断select方法的,当注册队列或取消注册队列发生变化时需要调用
        wakeup();

        // Now, we wait until this request is completed.
        request.awaitUninterruptibly();

        if (request.getException() != null) {
            throw request.getException();
        }

        // Update the local addresses.
        // setLocalAddresses() shouldn't be called from the worker thread
        // because of deadlock.
        // 更新本地绑定地址
        Set<SocketAddress> newLocalAddresses = new HashSet<SocketAddress>();

        for (H handle:boundHandles.values()) {
            newLocalAddresses.add(localAddress(handle));
        }
        
        return newLocalAddresses;
    }
/**
     * Starts the inner Acceptor thread.
     */
    private void startupAcceptor() {
        if (!selectable) {
            registerQueue.clear();
            cancelQueue.clear();
            flushingSessions.clear();
        }

        synchronized (lock) {
            if (acceptor == null) {
            	//开启执行线程
                acceptor = new Acceptor();
                executeWorker(acceptor);
            }
        }
    }

/**
     * This private class is used to accept incoming connection from 
     * clients. It's an infinite loop, which can be stopped when all
     * the registered handles have been removed (unbound). 
     */
    private class Acceptor implements Runnable {
        public void run() {
            int nHandles = 0;
            lastIdleCheckTime = System.currentTimeMillis();

            while (selectable) {
                try {
                	//检测是否有SelectionKey已经可以被处理了
                    int selected = select();

                    //注册服务器sockets句柄,这样做的目的是将Selector的状态置于
                    //OP_ACCEPT,并绑定到所监听的端口上,表明接受了可以接收的来自客户端的连接请求
                    nHandles += registerHandles();

                    if (selected > 0) {
                    	//处理可以被处理的SelectionKey状态为OP_ACCEPT的服务器socket句柄集(即真正处理来自客户端的连接请求)
                        processReadySessions(selectedHandles());
                    }

                    long currentTime = System.currentTimeMillis();
                    flushSessions(currentTime);
                    //检查是否有取消连接的客户端请求
                    nHandles -= unregisterHandles();

                    notifyIdleSessions(currentTime);

                    if (nHandles == 0) {
                        synchronized (lock) {
                            if (registerQueue.isEmpty() && cancelQueue.isEmpty()) {
                            	//完成工作
                                acceptor = null;
                                break;
                            }
                        }
                    }
                } catch (Exception e) {
                    ExceptionMonitor.getInstance().exceptionCaught(e);

                    try {
                    	//线程休眠一秒
                        Thread.sleep(1000);
                    } catch (InterruptedException e1) {
                    }
                }
            }

            if (selectable && isDisposing()) {
            	//释放资源
                selectable = false;
                try {
                    destroy();
                } catch (Exception e) {
                    ExceptionMonitor.getInstance().exceptionCaught(e);
                } finally {
                    disposalFuture.setValue(true);
                }
            }
        }
    }

    @SuppressWarnings("unchecked")
    private void processReadySessions(Iterator<H> handles) {
    	//处理来自客户端的连接请求
        while (handles.hasNext()) {
            H h = handles.next();
            handles.remove();
            try {
                if (isReadable(h)) {
                	//selector读操作
                    readHandle(h);
                }

                if (isWritable(h)) {
                	//selector写操作
                    for (IoSession session : getManagedSessions().values()) {
                        scheduleFlush((T) session);
                    }
                }
            } catch (Throwable t) {
                ExceptionMonitor.getInstance().exceptionCaught(t);
            }
        }
    }




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值