轉:Mina2.0架構源碼剖析(七)

來源:互聯網
上載者:User

前面介紹完了org.apache.mina.core.session這個包,現在開始進入org.apache.mina.core. polling包。這個包裡包含了實現基於輪詢策略(比如NIO的select調用或其他類型的I/O輪詢系統調用(如epoll,poll,kqueue等)的基類。

先來看AbstractPollingIoAcceptor這個抽象基類,它繼承自AbstractIoAcceptor,兩個泛型參數分別是所處理的會話和伺服器端socket串連。底層的sockets會被不斷檢測,併當有任何一個socket需要被處理時就會被喚醒去處理。這個類封裝了伺服器端socket的bind,accept和dispose等動作,其成員變數Executor負責接受來自用戶端的串連請求,另一個AbstractPollingIoProcessor用於處理用戶端的I/O操作請求,如讀寫和關閉串連。

其最重要的幾個成員變數是:

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

先來看看當服務端調用bind後的處理過程:

protected final Set<SocketAddress> bind0(
            List<? extends SocketAddress> localAddresses) throws Exception {
        AcceptorOperationFuture request = new AcceptorOperationFuture(localAddresses);//註冊請求
        registerQueue.add(request);//加入註冊隊列中,等待worker處理
        //建立一個Worker執行個體,開始工作
        startupWorker();
        wakeup();
        request.awaitUninterruptibly();
        // 更新本地綁定地址
        Set<SocketAddress> newLocalAddresses = new HashSet<SocketAddress>();
        for (H handle : boundHandles.values()) {
            newLocalAddresses.add(localAddress(handle));
        }
        return newLocalAddresses;
    }

     真正的負責接收用戶端請求的工作都是Worker線程完成的,

private class Worker implements Runnable {
        public void run() {
            int nHandles = 0;
            while (selectable) {
                try {
                    // Detect if we have some keys ready to be processed
                    boolean selected = select();//檢測是否有SelectionKey已經可以被處理了
                    nHandles += registerHandles();//註冊伺服器sockets控制代碼,這樣做的目的是將Selector的狀態置於OP_ACCEPT,並綁定到所監聽的連接埠上,表明接受了可以接收的來自用戶端的串連請求,
                    if (selected) {
                        processHandles(selectedHandles());//處理可以被處理的SelectionKey狀態為OP_ACCEPT的伺服器socket控制代碼集(即真正處理來自用戶端的串連請求)
                    }
                    nHandles -= unregisterHandles();//檢查是否有取消串連的用戶端請求
                    if (nHandles == 0) {
                        synchronized (lock) {
                            if (registerQueue.isEmpty()
                                    && cancelQueue.isEmpty()) {//完成工作
                                worker = null;
                                break;
                            }
                        }
                    }
                } catch (Throwable e) {
                    ExceptionMonitor.getInstance().exceptionCaught(e);
                    try {
                        Thread.sleep(1000);//線程休眠一秒
                    } catch (InterruptedException e1) {
                        ExceptionMonitor.getInstance().exceptionCaught(e1);
                    }
                }
            }
            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();
                    }
                }
            }
        }
private int registerHandles() {//註冊伺服器sockets控制代碼
        for (;;) {
            AcceptorOperationFuture future = registerQueue.poll();
            Map<SocketAddress, H> newHandles = new HashMap<SocketAddress, H>();
            List<SocketAddress> localAddresses = future.getLocalAddresses();
            try {
                for (SocketAddress a : localAddresses) {
                    H handle = open(a);//開啟指定地址,返回伺服器socket控制代碼
                    newHandles.put(localAddress(handle), handle);//加入地址—伺服器socket映射表中
                }
                boundHandles.putAll(newHandles);//更新本地綁定地址集
                // and notify.
                future.setDone();//完成註冊過程
                return newHandles.size();
            } catch (Exception e) {
                future.setException(e);
            } finally {
                // Roll back if failed to bind all addresses.
                if (future.getException() != null) {
                    for (H handle : newHandles.values()) {
                        try {
                            close(handle);//關閉伺服器socket控制代碼
                        } catch (Exception e) {
                            ExceptionMonitor.getInstance().exceptionCaught(e);
                        }
                    }
                    wakeup();
                }
            }
        }
    }
        private void processHandles(Iterator<H> handles) throws Exception {//處理來自用戶端的串連請求
            while (handles.hasNext()) {
                H handle = handles.next();
                handles.remove();
                T session = accept(processor, handle);//為一個伺服器socket控制代碼handle真正接收來自用戶端的請求,在給定的所關聯的processor上返回會話session
                if (session == null) {
                    break;
                }
                finishSessionInitialization(session, null, null);//結束會話初始化
                // add the session to the SocketIoProcessor
                session.getProcessor().add(session);
            }
        }
    }

     這個類中有個地方值得注意,就是wakeup方法,它是用來中斷select方法的,當註冊隊列或取消註冊隊列發生變化時需要調用它,可以參看本類的一個子類NioSocketAcceptor的實現:

    protected boolean select() throws Exception {
        return selector.select() > 0;
    }
    protected void wakeup() {
        selector.wakeup();
    }

     我們可以查閱jdk文檔,它對Selector的select方法有如下解釋:選擇一組鍵,其相應的通道已為 I/O 操作準備就緒。 此方法執行處於阻塞模式的選擇操作。僅在至少選擇一個通道、調用此選取器的 wakeup 方法、當前的線程已中止,或者給定的逾時期滿(以先到者為準)後此方法才返回。

參考資料

1,《Java NIO非阻塞伺服器樣本

 

作者:phinecos(洞庭散人)
出處:http://phinecos.cnblogs.com/
本文著作權歸作者和部落格園共有,歡迎轉載,但請保留此段聲明,並在文章頁面明顯位置給出原文串連。

作者:洞庭散人

出處:http://phinecos.cnblogs.com/    

本部落格遵從Creative Commons Attribution 3.0 License,若用於非商業目的,您可以自由轉載,但請保留原作者資訊和文章連結URL。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.