Mina主体逻辑流程

Mina也是一个one loop per thread的Reactor框架,关于这部分的知识可以看看《muduo网络库》这本书,Mina的优化什么的我看的不是很仔细,而且很多看不懂。这一篇博客主要从上层代码走一下Mina的主要逻辑流程。

简单介绍

Mina有几个主要的组件,分别是IoService,IoBuffer,IoFilter,IoHandler,IoSession,IoFuture(这部分简要介绍了参考资料中关于Mina的资料,可详细阅读参考资料

Mina的命名规范都是一个IoXXX接口,然后AbstractIoXXX定义主要逻辑过程的抽象类,然后就是具体的实现一般是NIOXXX

  • IoBuffer是一个抽象类,基本是对Java NIO的Buffer的封装使用,基本上只有setAllocator的一些实现AbstractIoBuffer 是IoBuffer的具体实现类,包含了expand和shrink以及put和get的方法

    • IoBufferAllocator是一个接口,具体实现有两个,内部类中包含了AbstractIoBuffer 的具体实现:

    SimpleBufferAllocator最基本的使用

    CachedBuffer如果频繁的扩充,那么就会多机器有压力,所以提前以2的幂去存储一堆已经生成的Buffer Map,存到ThreadLocal中,然后直接调用

  • IoService 用来管理各种IO服务,在mina中,这些服务可以包括session、filter、handler等

    AbstractIoService 负责初始化组建,关闭,初始化session(使用IoService中的属性最后去初始化AttributeMap),以及初始化一些IoService中包含的一些属性。

整体代码流程

public class MinaAcceptorThread implements Runnable {
    @Override
    public void run() {
        MinaClientHandler handler = new MinaClientHandler();
        NioSocketAcceptor acceptor = new NioSocketAcceptor();
        acceptor.setReuseAddress(true);
        acceptor.getFilterChain().addLast("protocol", new ProtocolCodecFilter(new IMCodeFactory(false)));
        acceptor.setDefaultLocalAddress(new InetSocketAddress(PathConstant.PORT));
        acceptor.setHandler(handler);
        try {
            acceptor.bind();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

NioSocketAcceptor会在初始化时调用

protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,
        Class<? extends IoProcessor<S>> processorClass) {
    this(sessionConfig, null, new SimpleIoProcessorPool<S>(processorClass),
            true);
}

NioSocketAcceptor中的selector只负责接收新的连接,具体的one loop per thread是由SimpleIoProcessorPool实现的。

SimpleIoProcessorPool中默认的线程池this.executor = Executors.newCachedThreadPool();SimpleIoProcessorPool中的pool是提前生成的CPU个数+1的NIOProcessor

扫描二维码关注公众号,回复: 2564342 查看本文章

NioSocketAcceptor接收到新的连接时执行

if (selected > 0) {
    // We have some connection request, let's process 
    // them here. 
    processHandles(selectedHandles());
}

初始化session的过程没有细看

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

        if (session == null) {
            break;
        }

        initSession(session, null, null);

        // add the session to the SocketIoProcessor
        session.getProcessor().add(session);
    }
}

加入SimpleIoProcessorPool的时候会将session与processor绑定,也就是连接绑定processor。

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 = 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;
    }

SimpleIoProcessorPool中的pool是提前生成的CPU个数+1的NIOProcessor

public final void add(S session) {
        if (disposed || disposing) {
            throw new IllegalStateException("Already disposed.");
        }

        // Adds the session to the newSession queue and starts the worker
        newSessions.add(session);
        startupProcessor();
    }

接下来就是执行AbstractPollingIoProcessor中内部的Processor类,也就是在线程池中

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

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

            if (processorRef.compareAndSet(null, processor)) {
                executor.execute(new NamePreservingRunnable(processor, threadName));
            }
        }

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

这部分也就是每个NIO具体在select分配过来的网络连接

nSessions += handleNewSessions();//创建FilterChain过程
....
//处理过程  
if (selected > 0) {
    process();
}

具体处理数据的过程

private void process(S session) {
        // Process Reads
        if (isReadable(session) && !session.isReadSuspended()) {
            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);
            }
        }
    }

以read为例

private void read(S session) {
        ...
            if (readBytes > 0) {
                IoFilterChain filterChain = session.getFilterChain();
                filterChain.fireMessageReceived(buf);
                buf = null;

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

调用IoFilterChain就开始了对数据解析以及最终用户通过IoHandler得到具体的网络通信数据。FilterChain的流程在DefaultIoFilterChain中定义

public void fireMessageReceived(Object message) {
        if (message instanceof IoBuffer) {
            session.increaseReadBytes(((IoBuffer) message).remaining(), System
                    .currentTimeMillis());
        }

        Entry head = this.head;
        callNextMessageReceived(head, session, message);
    }

    private void callNextMessageReceived(Entry entry, IoSession session,
            Object message) {
        try {
            IoFilter filter = entry.getFilter();
            NextFilter nextFilter = entry.getNextFilter();
            filter.messageReceived(nextFilter, session,
                    message);
        } catch (Throwable e) {
            fireExceptionCaught(e);
        }
    }

CumulativeProtocolDecoder可以帮助你积累未收完的一条消息,doDecode返回false会使用IoBuffer缓存该消息。

public void messageReceived(NextFilter nextFilter, IoSession session,
            Object message) throws Exception {
        LOGGER.debug( "Processing a MESSAGE_RECEIVED for session {}", session.getId() );

        if (!(message instanceof IoBuffer)) {
            nextFilter.messageReceived(session, message);
            return;
        }

        IoBuffer in = (IoBuffer) message;
        ProtocolDecoder decoder = factory.getDecoder(session);
        ProtocolDecoderOutput decoderOut = getDecoderOut(session, nextFilter);

        // Loop until we don't have anymore byte in the buffer,
        // or until the decoder throws an unrecoverable exception or 
        // can't decoder a message, because there are not enough 
        // data in the buffer
        while (in.hasRemaining()) {
            int oldPos = in.position();

            try {
                synchronized (decoderOut) {
                    // Call the decoder with the read bytes
                    decoder.decode(session, in, decoderOut);
                }

                // Finish decoding if no exception was thrown.
                decoderOut.flush(nextFilter, session);
            } catch (Throwable t) {
              ...

最后看看在DefaultIoFilterChain中如何实现IoFilterChain与IoHandler结合成一个链条。DefaultIoFilterChain中的Entry最后由DefaultIoFilterChainImpl中buildFilterChain把Entry插入IoFilterChain。Entry中包含了IoFilter,Entry是IoFilterChain的包装

接上面创建FilterChain过程

nSessions += handleNewSessions();

handlerNewSessions()->addNow()会将初始化时addLast的IoFilterChain(也就是一开始代码中的acceptor.getFilterChain().addLast(“protocol”, new ProtocolCodecFilter(new IMCodeFactory(false)));)

通过bulider生成DefaultIoFilterChain中Entry的链子

public void buildFilterChain(IoFilterChain chain) throws Exception {
        for (Entry e : entries) {
            chain.addLast(e.getName(), e.getFilter());
        }
    }

DefaultIoFilterChain在初始化时会

public DefaultIoFilterChain(AbstractIoSession session) {
        if (session == null) {
            throw new IllegalArgumentException("session");
        }

        this.session = session;
        head = new EntryImpl(null, null, "head", new HeadFilter());
        tail = new EntryImpl(head, null, "tail", new TailFilter());
        head.nextEntry = tail;
    }

Head主要是flush发送缓冲区(具体关于send的过程没有详细阅读)

if (!s.isWriteSuspended()) {
    s.getProcessor().flush(s);
}

Tail是IoHandler,看一眼就明白了

private static class TailFilter extends IoFilterAdapter {
        @Override
        public void sessionCreated(NextFilter nextFilter, IoSession session)
                throws Exception {
            try {
                session.getHandler().sessionCreated(session);
            } finally {
                // Notify the related future.
                ConnectFuture future = (ConnectFuture) session
                        .removeAttribute(SESSION_CREATED_FUTURE);
                if (future != null) {
                    future.setSession(session);
                }
            }
        }

疑惑:

  1. 为什么要synchronized (decoderOut)每一个session都被指定的processpr执行,不应该出现多线程的问题啊?
  2. IoService 中的线程池是做什么的
  3. Mina中的多线程问题

下一篇博客内容

  • 知道了主要的Mina流程,下一篇我将比较详细介绍一下各个组件以及之间的关系
  • Mina在实现应用层协议时应该注意哪些问题

参考资料

系列介绍

Mina官方文档

资料

资料

Mina实现自定义应用层协议

Java NIO基础

多selector介绍

猜你喜欢

转载自blog.csdn.net/WSRspirit/article/details/71104770