mina学习2

来源:互联网 发布:linux 程序运行权限 编辑:程序博客网 时间:2024/04/30 13:39


Acceptor线程在等待新socket进入时,执行run()流程如下:


AbstractPollingIoAcceptor$Acceptor.processHandles(Iterator<H>)
AbstractPollingIoAcceptor$Acceptor.run()
NamePreservingRunnable.run()
ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker)
ThreadPoolExecutor$Worker.run()
Thread.run()


当有新socket连接时,关键代码如下:

AbstractPollingIoAcceptor$Acceptor.processHandles(Iterator<H>) 用来处理新socket.


  private void processHandles(Iterator<H> handles) throws Exception
        {
            while (handles.hasNext())
            {
                H handle = handles.next();
                handles.remove();

                // Associates a new created connection to a processor,
                // and get back a session
                S session = accept(processor, handle);  //生成新IoSession
                //当有一个新socket链接时,返回一个IoSession
                if (session == null)
                {
                    continue;
                }
                initSession(session, null, null);  //初始化IoSession

                // add the session to the SocketIoProcessor
                //当Acceptor发现新的socket,把socket和ioproces相关联。所有io事件由ioprocess处理
                session.getProcessor().add(session);

            }
        }



    private IoProcessor<S> getProcessor(S session)
    {
        IoProcessor<S> processor = (IoProcessor<S>) session.getAttribute(PROCESSOR);

        if (processor == null) {
            if (disposed || disposing) {
                throw new IllegalStateException("A disposed processor cannot be accessed.");
            }
            //把processor和session相关联。根据session id和proceor pool 的大小来决定
            processor = pool[Math.abs((int) session.getId()) % pool.length];


            if (processor == null)

            {
                throw new IllegalStateException("A disposed processor cannot be accessed.");
            }

            session.setAttributeIfAbsent(PROCESSOR, processor);
        }

        return processor;
    }

NioProcessor(AbstractPollingIoProcessor<S>).add(S) 把IoSession加入到Processor线程中.


 public final void add(S session)
    {
        if (disposed || disposing)
        {
            throw new IllegalStateException("Already disposed.");
        }
        //当IoAcceptor接受到新的IoSession中,把IoSession和IoProcessor相关联
        // Adds the session to the newSession queue and starts the worker
        newSessions.add(session);
        startupProcessor();

    }


    private void startupProcessor()
    {
        Processor processor = processorRef.get();

        if (processor == null)
        {
            processor = new Processor();

            if (processorRef.compareAndSet(null, processor))
            {
                //触发一个新的ioprocess来执行iosession
                executor.execute(new NamePreservingRunnable(processor, threadName)); //Acceptor线程到此把新IoSession与IoProcessor线程相关联。
            }

        }

        // Just stop the select() and start it again, so that the processor
        // can be activated immediately.
        wakeup();
    }



    /**
     * The main loop. This is the place in charge to poll the Selector, and to
     * process the active sessions. It's done in
     * - handle the newly created sessions
     * -
     */

   //内部类Processor线程是处理IO读写操作的主要循环类。在Processor中,不断轮训Select()操作来判断IO操作动作的完成。
    private class Processor implements Runnable
    {
        public void run()
        {
            assert (processorRef.get() == this);

            int nSessions = 0;
            lastIdleCheckTime = System.currentTimeMillis();

            for (;;)
            {
                try
                {
                    // This select has a timeout so that we can manage
                    // idle session when we get out of the select every
                    // second. (note : this is a hack to avoid creating
                    // a dedicated thread).
                    //在run()方法中执行 select()方法
                    long t0 = System.currentTimeMillis();
                    int selected = select(SELECT_TIMEOUT);
                    long t1 = System.currentTimeMillis();
                    long delta = (t1 - t0);

                    if ((selected == 0) && !wakeupCalled.get() && (delta < 100))
                    {
                        // Last chance : the select() may have been
                        // interrupted because we have had an closed channel.
                        if (isBrokenConnection())
                        {
                            LOG.warn("Broken connection");

                            // we can reselect immediately
                            // set back the flag to false
                            wakeupCalled.getAndSet(false);

                            continue;
                        }
                        else
                        {
                            LOG.warn("Create a new selector. Selected is 0, delta = " + (t1 - t0));
                            // Ok, we are hit by the nasty epoll
                            // spinning.
                            // Basically, there is a race condition
                            // which causes a closing file descriptor not to be
                            // considered as available as a selected channel, but
                            // it stopped the select. The next time we will
                            // call select(), it will exit immediately for the same
                            // reason, and do so forever, consuming 100%
                            // CPU.
                            // We have to destroy the selector, and
                            // register all the socket on a new one.
                            registerNewSelector();
                        }

                        // Set back the flag to false
                        wakeupCalled.getAndSet(false);

                        // and continue the loop
                        continue;
                    }

                    // Manage newly created session first
                    nSessions += handleNewSessions();

                    updateTrafficMask();

                    // Now, if we have had some incoming or outgoing events,
                    // deal with them
                    //当select()函数执行完操作时,有IO操作事件完成。
                    if (selected > 0)
                    {
                        process(); //在这里只要有IO操作完成时,就不断处理IO操作。与JBoss Netty操作类似。
                    }

                    // Write the pending requests
                    long currentTime = System.currentTimeMillis();
                    flush(currentTime);

                    // And manage removed sessions
                    nSessions -= removeSessions();

                    // Last, not least, send Idle events to the idle sessions
                    notifyIdleSessions(currentTime);

                    // Get a chance to exit the infinite loop if there are no
                    // more sessions on this Processor
                    if (nSessions == 0) {
                        processorRef.set(null);

                        if (newSessions.isEmpty() && isSelectorEmpty()) {
                            // newSessions.add() precedes startupProcessor
                            assert (processorRef.get() != this);
                            break;
                        }

                        assert (processorRef.get() != this);

                        if (!processorRef.compareAndSet(null, this)) {
                            // startupProcessor won race, so must exit processor
                            assert (processorRef.get() != this);
                            break;
                        }

                        assert (processorRef.get() == this);
                    }

                    // Disconnect all sessions immediately if disposal has been
                    // requested so that we exit this loop eventually.
                    if (isDisposing()) {
                        for (Iterator<S> i = allSessions(); i.hasNext();) {
                            scheduleRemove(i.next());
                        }

                        wakeup();
                    }
                } catch (ClosedSelectorException cse) {
                    // If the selector has been closed, we can exit the loop
                    // But first, dump a stack trace
                    ExceptionMonitor.getInstance().exceptionCaught(cse);
                    break;
                } catch (Exception e) {
                    ExceptionMonitor.getInstance().exceptionCaught(e);

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e1) {
                        ExceptionMonitor.getInstance().exceptionCaught(e1);
                    }
                }
            }

            try {
                synchronized (disposalLock) {
                    if (disposing) {
                        doDispose();
                    }
                }
            } catch (Exception e) {
                ExceptionMonitor.getInstance().exceptionCaught(e);
            } finally {
                disposalFuture.setValue(true);
            }
        }
    }



  /**
     * Deal with session ready for the read or write operations, or both.
     */

   //用于处理IoSession中对于IO完成的读写操作。
    private void process(S session)
    {
        // Process Reads
        //真正执行IO读写操作的地方
        if (isReadable(session) && !session.isReadSuspended())
        {
            //执行IO读取操作
            read(session);
        }

        // Process writes
        if (isWritable(session) && !session.isWriteSuspended())
        {
            // add the session to the queue, if it's not already there
            if (session.setScheduledForFlush(true))
            {
                flushingSessions.add(session);
            }
        }
    }



    //在IoProcessor中真正执行IO读取操作的地方
    private void read(S session)
    {
        IoSessionConfig config = session.getConfig();
        //socket中可以读取字节数量
        int bufferSize = config.getReadBufferSize();
        IoBuffer buf = IoBuffer.allocate(bufferSize);
        //判断数据包是否分包
        final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation();

        try {
            int readBytes = 0; //可以读取最大数据。
            int ret;

            try {
                if (hasFragmentation) {

                    while ((ret = read(session, buf)) > 0) {
                        readBytes += ret;

                        if (!buf.hasRemaining()) {
                            break;
                        }
                    }
                } else {
                    ret = read(session, buf);

                    if (ret > 0) {
                        readBytes = ret;
                    }
                }
            } finally {
                buf.flip();
            }

            if (readBytes > 0)
            {
                //在session相关联的FilterChain中相关联的过滤链
                IoFilterChain filterChain = session.getFilterChain();
                filterChain.fireMessageReceived(buf);
  //当线程执行到IO操作读取时,不断读取缓冲区数,并通知Handler来处理数据逻辑。所以,在这里没有处理分包和逻辑处理。需要在Handler中对于分包和逻辑包来处理。
                buf = null;

                if (hasFragmentation) {
                    if (readBytes << 1 < config.getReadBufferSize()) {
                        session.decreaseReadBufferSize();
                    } else if (readBytes == config.getReadBufferSize()) {
                        session.increaseReadBufferSize();
                    }
                }
            }

            if (ret < 0) {
                // scheduleRemove(session);
                IoFilterChain filterChain = session.getFilterChain();
                filterChain.fireInputClosed();
            }
        } catch (Exception e) {
            if (e instanceof IOException) {
                if (!(e instanceof PortUnreachableException)
                        || !AbstractDatagramSessionConfig.class.isAssignableFrom(config.getClass())
                        || ((AbstractDatagramSessionConfig) config).isCloseOnPortUnreachable()) {
                    scheduleRemove(session);
                }
            }

            IoFilterChain filterChain = session.getFilterChain();
            filterChain.fireExceptionCaught(e);
        }
    }




















0 0
原创粉丝点击