mina框架分析---2

processHandles

上一篇文章分析到Acceptor中的processHandles,该函数是处理客户端请求的核心函数,定义在Acceptor中,

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

                S session = accept(processor, handle);

                if (session == null) {
                    continue;
                }

                initSession(session, null, null);
                session.getProcessor().add(session);
            }
        }

accept用于构造一个Session,定义在NioSocketAcceptor中,传入的参数processor是前面在构造函数中构造的SimpleIoProcessorPool,handle就是ServerSocketChannel,

    protected NioSession accept(IoProcessor<NioSession> processor, ServerSocketChannel handle) throws Exception {

        SocketChannel ch = handle.accept();
        return new NioSocketSession(this, processor, ch);
    }

这里就是获取客户端的连接SocketChannel,然后构造一个NioSocketSession,该构造函数就是简单的赋值,这里不往下看了,重点是在构造NioSocketSession时,创建了一个DefaultIoFilterChain,后面要重点用到这个Filter链。
回到processHandles,接下来调用initSession进行初始化,然后注册该NioSocketSession。这里getProcessor返回前面创建的SimpleIoProcessorPool,其add函数如下

    public final void add(S session) {
        getProcessor(session).add(session);
    }

这里的getProcessor返回前面在SimpleIoProcessorPool构造函数中创建的NIOProcessor,然后调用其add函数,

    public final void add(S session) {
        newSessions.add(session);
        startupProcessor();
    }

这里首先将前面创建的NioSocketSession添加进newSessions中,然后调用startupProcessor开始处理。

startupProcessor

startupProcessor定义在AbstractPollingIoProcessor中,

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

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

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

这里就是尝试获取一个Processor,如果没有,就创建一个新的Processor线程,用于处理刚刚的NioSocketSession,因此下面开始分析Processor的run函数,

        public void run() {

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

            for (;;) {
                try {
                    long t0 = System.currentTimeMillis();
                    int selected = select(SELECT_TIMEOUT);
                    long t1 = System.currentTimeMillis();
                    long delta = (t1 - t0);

                    if ((selected == 0) && !wakeupCalled.get() && (delta < 100)) {
                        if (isBrokenConnection()) {
                            wakeupCalled.getAndSet(false);
                            continue;
                        } else {
                            registerNewSelector();
                        }
                        wakeupCalled.getAndSet(false);
                        continue;
                    }

                    nSessions += handleNewSessions();

                    updateTrafficMask();
                    if (selected > 0) {
                        process();
                    }

                    long currentTime = System.currentTimeMillis();
                    flush(currentTime);
                    nSessions -= removeSessions();

                    notifyIdleSessions(currentTime);

                    if (nSessions == 0) {
                        processorRef.set(null);

                        if (newSessions.isEmpty() && isSelectorEmpty()) {
                            break;
                        }

                        if (!processorRef.compareAndSet(null, this)) {
                            break;
                        }
                    }

                    if (isDisposing()) {
                        for (Iterator<S> i = allSessions(); i.hasNext();) {
                            scheduleRemove(i.next());
                        }

                        wakeup();
                    }
                } catch (Exception e) {

                }
            }
        }

每个NIOProcessor会重新构造一个Selector,第一次执行该函数时,由于selected =0,delta<100(无事件),但是由于wakeupCalled被初始化为true,因此直接执行到handleNewSessions。handleNewSessions添加需要处理的Session,然后调用process进行处理,处理完毕后调用flush向客户端发送数据,接着调用removeSessions移除相应的Session,最后调用notifyIdleSessions处理Idle状态的Session,下面重点分析handleNewSessions、flush和removeSessions三个函数,其余的函数可以参照源码自行分析。

handleNewSessions

handleNewSessions定义在AbstractPollingIoProcessor中,

    private int handleNewSessions() {
        int addedSessions = 0;

        for (S session = newSessions.poll(); session != null; session = newSessions.poll()) {
            if (addNow(session)) {
                addedSessions++;
            }
        }

        return addedSessions;
    }

该函数从newSessions获取注册的NioSocketSession,然后调用addNow将该NioSocketSession注册到Selector中。addNow定义在AbstractPollingIoProcessor中,

    private boolean addNow(S session) {
        boolean registered = false;

        try {
            init(session);
            registered = true;

            IoFilterChainBuilder chainBuilder = session.getService().getFilterChainBuilder();
            chainBuilder.buildFilterChain(session.getFilterChain());

            IoServiceListenerSupport listeners = ((AbstractIoService) session.getService()).getListeners();
            listeners.fireSessionCreated(session);
        } catch (Exception e) {

        }

        return registered;
    }

init定义在NIOProcessor中,该函数的主要作用就是往Selector中注册OP_READ事件。

    protected void init(NioSession session) throws Exception {
        SelectableChannel ch = (SelectableChannel) session.getChannel();
        ch.configureBlocking(false);
        session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ, session));
    }

session.getService()返回NioSocketAcceptor,查看上一章的构造函数,可以知道,这里getFilterChainBuilder返回的是DefaultIoFilterChainBuilder(在AbstractIoService类中),而session.getFilterChain()返回的是DefaultIoFilterChain(在NioSession构造函数中),因此下面看DefaultIoFilterChainBuilder的buildFilterChain函数,

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

这里就不往下看了,简而言之就是构造一个监听器的链表。

回到run函数中,接下来执行updateTrafficMask,定义在AbstractPollingIoProcessor中,该函数的作用就是重新更新Selector监听的事件,例如当用户不需要读数据时,就将读事件OP_READ从Selector中删除,以减少Selector监听的事件数量。再往下就是调用process处理事件了,该函数放在下一章分析。再接下来的flush用于发送数据,

flush

flush定义在AbstractPollingIoProcessor中,

    private void flush(long currentTime) {

        do {
            S session = flushingSessions.poll();

            if (session == null) {
                break;
            }

            session.unscheduledForFlush();
            SessionState state = getState(session);

            switch (state) {
            case OPENED:
                try {
                    boolean flushedAll = flushNow(session, currentTime);

                    if (flushedAll && !session.getWriteRequestQueue().isEmpty(session)
                            && !session.isScheduledForFlush()) {
                        scheduleFlush(session);
                    }
                } catch (Exception e) {

                }
                break;

            case CLOSING:
                break;

            case OPENING:
                scheduleFlush(session);
                return;

            default:
                throw new IllegalStateException(String.valueOf(state));
            }

        } while (!flushingSessions.isEmpty());
    }

flushingSessions中保存了需要发送数据的Session,该函数首先依次从flushingSessions取出NioSocketSession,然后调用unscheduledForFlush设置其scheduledForFlush标志位,表是是否允许flush,接着调用getState获取该Session的状态,这里首先假设该Session处于OPENED状态,则调用flushNow,
flushNow定义在AbstractPollingIoProcessor中,

    private boolean flushNow(S session, long currentTime) {

        final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation();

        final WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue();

        final int maxWrittenBytes = session.getConfig().getMaxReadBufferSize()
                + (session.getConfig().getMaxReadBufferSize() >>> 1);
        int writtenBytes = 0;
        WriteRequest req = null;

        try {
            setInterestedInWrite(session, false);

            do {
                req = session.getCurrentWriteRequest();

                int localWrittenBytes = 0;
                Object message = req.getMessage();

                if (message instanceof IoBuffer) {
                    localWrittenBytes = writeBuffer(session, req, hasFragmentation, maxWrittenBytes - writtenBytes,
                            currentTime);

                    if ((localWrittenBytes > 0) && ((IoBuffer) message).hasRemaining()) {
                        writtenBytes += localWrittenBytes;
                        setInterestedInWrite(session, true);
                        return false;
                    }
                } else if (message instanceof FileRegion) {
                    localWrittenBytes = writeFile(session, req, hasFragmentation, maxWrittenBytes - writtenBytes,
                            currentTime);
                    if ((localWrittenBytes > 0) && (((FileRegion) message).getRemainingBytes() > 0)) {
                        writtenBytes += localWrittenBytes;
                        setInterestedInWrite(session, true);
                        return false;
                    }
                } else {

                }

                if (localWrittenBytes == 0) {
                    setInterestedInWrite(session, true);
                    return false;
                }

                writtenBytes += localWrittenBytes;

                if (writtenBytes >= maxWrittenBytes) {
                    scheduleFlush(session);
                    return false;
                }

                if (message instanceof IoBuffer) {
                    ((IoBuffer) message).free();
                }
            } while (writtenBytes < maxWrittenBytes);
        } catch (Exception e) {

        }

        return true;
    }

首先获得hasFragmentation用于判断传输的数据是否可分割,然后设置本次传输的最大字节数maxWrittenBytes为读缓存最大字节数的1.5倍,然后调用setInterestedInWrite暂时关闭NIO中的写监听事件,暂停写(因为现在要往缓存中写入数据了),再接着从WriteRequest(req)中获取需要写入的数据,然后判断该数据是普通的数据还是文件,如果是普通数据,则调用writeBuffer执行写操作,如果是文件,则调用writeFile,这两个函数都返回写入的字节数,用于判断是否可写,如果数据全部写入,则调用free释放该缓存。writeBuffer和writeFile就不往下看代码了,简单来说就是获得NIO中的Channel,然后把数据写到Channel中,可以查看网上很多关于NIO的资料。
回到flush函数中,后面的if的意思是,如果写缓存中还有空间并且还有数据需要写入,则调用scheduleFlush继续讲Session中的数据填入写缓存中。

removeSessions

往上回到run函数中,由于处理完了相应的事件,并且把需要发送的数据添加进缓存中,接下来就调用removeSessions移除需要移除的Session,定义在AbstractPollingIoProcessor中,

    private int removeSessions() {
        int removedSessions = 0;

        for (S session = removingSessions.poll(); session != null; session = removingSessions.poll()) {
            SessionState state = getState(session);

            switch (state) {
            case OPENED:
                if (removeNow(session)) {
                    removedSessions++;
                }
                break;

            case CLOSING:
                break;

            case OPENING:
                newSessions.remove(session);
                if (removeNow(session)) {
                    removedSessions++;
                }
                break;

            default:
                throw new IllegalStateException(String.valueOf(state));
            }
        }

        return removedSessions;
    }

需要移除的Session会保存在removingSessions中,这里依次取出该NioSocketSession,然后判断状态,调用removeNow移除该Session,这里就不往下看了。

到这里,processHandles函数就分析完了,下一章将会重点分析process函数,该函数是处理客户端请求的主要函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值