tomcat源碼分析(三)一次http請求的旅行-從Socket提及

tomcat源碼分析()一次http請求的旅行apache

http請求旅行以前,咱們先來準備下咱們所須要的工具。首先要說的就是Connector,其做爲Service的子容器,承擔着http請求的核心功能。那咱們先來準備下一啊吧。數組

咱們知道一次網絡請求過來以後,從網絡的角度來看,是通過物理層→鏈路層→網絡層->傳輸層->應用層,以下圖所示。tomcat

            

 

 

 

  咱們所熟知的的Socket處於TCP(傳輸層),操做系統爲咱們提供來一套API來操做Socket,而tomcat其任務就是針對傳輸層過來的Socket進行包裝,並實現應用層的協議,最多見的應用層協議應該算是http協議了。接下來就來具體看看tomcat是如何實現http協議(實際上tomcat還實現了ajp協議以及處理請求的。服務器

咱們這裏以最多見的BIO(阻塞試IO)的方式來分析。咱們先來看看tomcat是怎麼處理TCP鏈接的。在org.apche.tomcat.util.net包主要是用於處理網絡請求的,即對TCP的處理。網絡

  首先咱們來看一下org.apache.tomcat.util.net.AbstractEndPoint這個類。在Tomcat的對請求的設計當中,由專門的線程接受TCP鏈接,並直接將TCP鏈接轉交給工做線程。在AbstrctEndPoint中有一個抽象的靜態內部類咱們來一塊兒看一下。app

public abstract static class Acceptor implements Runnable {
        public enum AcceptorState {
            NEW, RUNNING, PAUSED, ENDED
        }

        protected volatile AcceptorState state = AcceptorState.NEW;
        public final AcceptorState getState() {
            return state;
        }

        private String threadName;
        protected final void setThreadName(final String threadName) {
            this.threadName = threadName;
        }
        protected final String getThreadName() {
            return threadName;
        }
    }

 

  能夠看出在這個靜態內部類中並無實現run()方法,其實現交給子類來實現。在Tomcat中實際定義來一個 Acceptor數組來表示一組接受TCP鏈接的線程。咱們在簡單看一下其啓動這個接受線程的代碼實現。socket

 

protected final void startAcceptorThreads() {
        int count = getAcceptorThreadCount();
        acceptors = new Acceptor[count];

        for (int i = 0; i < count; i++) {
            acceptors[i] = createAcceptor();
            String threadName = getName() + "-Acceptor-" + i;
            acceptors[i].setThreadName(threadName);
            Thread t = new Thread(acceptors[i], threadName);
            t.setPriority(getAcceptorThreadPriority());
            t.setDaemon(getDaemon());
            t.start();
        }
    }

 

  其中count這個咱們是能夠在server.xml中去配置的,通常狀況下,會配置1-2。也就是說接受TCP鏈接的線程也只是1-2個。ide

  說到這裏,咱們也應該來講重點來,就是接受線程是如何具體工做的,咱們來看JIOEndPoint,這個類是AbstractEndPoint的子類,也是設計來處理TCP鏈接的,這個類實現了一個簡單的服務器,會有一到2個監聽線程來監聽Socket,對於每個TCP鏈接,都會從建立一個工做線程來處理。工具

剛剛咱們說道AbstractEndPoint中的抽象靜態內部類Acceptor,在其子類JIOEndPoint中也存在一個內部類,繼承自Acceptor,並實現來run();方法。咱們來看一下。oop

 

 

protected class Acceptor extends AbstractEndpoint.Acceptor {

        @Override
        public void run() {

            int errorDelay = 0;

            // Loop until we receive a shutdown command
            while (running) {

                // Loop if endpoint is paused
                while (paused && running) {
                    state = AcceptorState.PAUSED;
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }

                if (!running) {
                    break;
                }
                state = AcceptorState.RUNNING;

                try {
                    //if we have reached max connections, wait
                    countUpOrAwaitConnection();

                    Socket socket = null;
                    try {
                        // Accept the next incoming connection from the server
                        // socket
                        socket = serverSocketFactory.acceptSocket(serverSocket);
                    } catch (IOException ioe) {
                        countDownConnection();
                        // Introduce delay if necessary
                        errorDelay = handleExceptionWithDelay(errorDelay);
                        // re-throw
                        throw ioe;
                    }
                    // Successful accept, reset the error delay
                    errorDelay = 0;

                    // Configure the socket
                    if (running && !paused && setSocketOptions(socket)) {
                        // Hand this socket off to an appropriate processor
                        if (!processSocket(socket)) {
                            countDownConnection();
                            // Close socket right away
                            closeSocket(socket);
                        }
                    } else {
                        countDownConnection();
                        // Close socket right away
                        closeSocket(socket);
                    }
                } catch (IOException x) {
                    if (running) {
                        log.error(sm.getString("endpoint.accept.fail"), x);
                    }
                } catch (NullPointerException npe) {
                    if (running) {
                        log.error(sm.getString("endpoint.accept.fail"), npe);
                    }
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    log.error(sm.getString("endpoint.accept.fail"), t);
                }
            }
            state = AcceptorState.ENDED;
        }
    }

 

  其核心在接收到TCP鏈接以後,即在接收到Socket,會調用processSocket(Socket socket);這個方法。咱們再來關注一下這個方法。

 

protected boolean processSocket(Socket socket) {
        // Process the request from this socket
        try {
            SocketWrapper<Socket> wrapper = new SocketWrapper<Socket>(socket);
            wrapper.setKeepAliveLeft(getMaxKeepAliveRequests());
            wrapper.setSecure(isSSLEnabled());
            // During shutdown, executor may be null - avoid NPE
            if (!running) {
                return false;
            }
            getExecutor().execute(new SocketProcessor(wrapper));
        } catch (RejectedExecutionException x) {
            log.warn("Socket processing request was rejected for:"+socket,x);
            return false;
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            // This means we got an OOM or similar creating a thread, or that
            // the pool and its queue are full
            log.error(sm.getString("endpoint.process.fail"), t);
            return false;
        }
        return true;
    }

 

  其核心代碼在於 getExecutor().execute(new SocketProcessor(wrapper));getExecutor()會返回Executor對象(AbstractEndPointcreateExecutor()創建了線程池),由線程池中的線程來處理該Socket。咱們再來看一下SocketProccessor這個在JIOEndPoint中的內部類,這個類(注意此時已經在工做線程之中)中核心代碼

 

            if ((state != SocketState.CLOSED)) {
                        if (status == null) {
                            state = handler.process(socket, SocketStatus.OPEN_READ);
                        } else {
                            state = handler.process(socket,status);
                        }
                    }

   從中咱們能夠看到實際處理又交給來Handler來處理,那麼Handler怎麼處理的,咱們會在下一節當中具體闡述。這一節就先講述到這裏,下一節會講述handler具體處理過程。

相關文章
相關標籤/搜索