上文說了簡單的servlet解析過程。實際上,tomcat在解析servlet的 時候是吧鏈接器定位爲知足如下三個條件:css
一、必須事先接口org.apache.catalina.Connectorjava
2. 必須建立請求對象,該請求對象的類必須實現接口org.apache.catalina.Request。 node
3. 必須建立響應對象,該響應對象的類必須實現接口org.apache.catalina.Response。web
tomcat的鏈接器有不少種類:Coyote、mode_jk、mod_jk2和mode_webapp等。apache
來自瀏覽器的請求類型是有區別的http/0.9 http/1.0 http/1.1.瀏覽器
http/1.1又叫作持久鏈接,上文中一次請求處理完畢就關閉了socket。然而,在現實的頁面請求中須要加載多種資源(js、img css)。若是每次請求都開啓關閉鏈接那將是很是耗時的事情。http/1.1可以讓瀏覽器和服務器保持一種持久化的鏈接,快速的相應請求。這樣,請求的形式就和以前不一樣,他是一塊編碼的形式,並使用特殊頭部transfer-encoding感知發送過來的數據信息。同時,若是瀏覽器有較大數據請求以前發送頭部信息Expect: 100-continue頭部到服務器,等待服務器的相應。若是服務器響應數據可以接受大數據請求,才真正的發送數據,避免先發送大數據而遭服務器拒絕而浪費了傳輸數據的帶寬資源。tomcat
本文重點說明鏈接器的演進。安全
鏈接器的演進主要包括瞭如下幾個方面:服務器
一、處理請求再也不只是一次處理一次請求,而是生成Processor池,用於處理多個鏈接請求。同事Processor處理器也再也不是每次請求新生成實例處理請求,而是從池子中獲取到一個處理器去完成請求。同時,實現了Processor處理方法異步化,讓鏈接器線程可以繼續接受其餘的請求。併發
二、處理器線程和鏈接器線程經過wait() notifyAll()的方式進行線程間通訊。
三、Processor處理器中,增長了標識符,KeepAlive、stopped和http11,爲處理器在處理的過程當中設定「路口」,及時相應請求的變化。
四、socket緩衝區大小再也不是像前文同樣設置爲定值,而是經過獲取鏈接器傳遞過來的參數設置緩衝區大小。
五、處理器的職能更加的豐富。
鏈接處理 parseConnection,針對不一樣的鏈接協議作不一樣的處理。
解析請求 parseRequest
解析頭部 parseHeaders
六、去掉了靜態處理器,暫時沒法接受靜態資源請求。
------------------------
一、鏈接器啓動:
HttpConnector connector = new HttpConnector(); SimpleContainer container = new SimpleContainer(); connector.setContainer(container); try { //初始化鏈接器,打開socket鏈接 connector.initialize(); //開啓監聽,開啓鏈接器線程、將處理器線程啓動併入隊列。 connector.start(); System.in.read(); } catch (Exception e) { e.printStackTrace(); }
1.1 初始化鏈接、打開socket鏈接(使用工廠模式)
public void initialize() throws LifecycleException { //初始化標誌,不能重複初始化 if (initialized) throw new LifecycleException ( sm.getString("httpConnector.alreadyInitialized")); this.initialized=true; Exception eRethrow = null; // Establish a server socket on the specified port try { //打開socket鏈接 serverSocket = open(); } catch (IOException ioe) { log("httpConnector, io problem: ", ioe); eRethrow = ioe; } catch (KeyStoreException kse) { log("httpConnector, keystore problem: ", kse); eRethrow = kse; } catch (NoSuchAlgorithmException nsae) { log("httpConnector, keystore algorithm problem: ", nsae); eRethrow = nsae; } catch (CertificateException ce) { log("httpConnector, certificate problem: ", ce); eRethrow = ce; } catch (UnrecoverableKeyException uke) { log("httpConnector, unrecoverable key: ", uke); eRethrow = uke; } catch (KeyManagementException kme) { log("httpConnector, key management problem: ", kme); eRethrow = kme; } if ( eRethrow != null ) throw new LifecycleException(threadName + ".open", eRethrow); } private ServerSocket open() throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException { // Acquire the server socket factory for this Connector //得到服務器socket工廠實例 ServerSocketFactory factory = getFactory(); // If no address is specified, open a connection on all addresses //若是沒有指定地址,在全部地址上打開一個鏈接 if (address == null) { log(sm.getString("httpConnector.allAddresses")); try { return (factory.createSocket(port, acceptCount)); } catch (BindException be) { throw new BindException(be.getMessage() + ":" + port); } } //在指定地址上打開一個鏈接 try { InetAddress is = InetAddress.getByName(address); log(sm.getString("httpConnector.anAddress", address)); try { return (factory.createSocket(port, acceptCount, is)); } catch (BindException be) { throw new BindException(be.getMessage() + ":" + address + ":" + port); } } catch (Exception e) { log(sm.getString("httpConnector.noAddress", address)); try { return (factory.createSocket(port, acceptCount)); } catch (BindException be) { throw new BindException(be.getMessage() + ":" + port); } } }
1.二、開啓監聽,開啓鏈接器線程、將處理器線程啓動併入隊列。
//爲鏈接器綁定指定數量的處理器 public void start() throws LifecycleException { //判斷該線程的connect開啓狀態,避免重複開啓 if (started) throw new LifecycleException (sm.getString("httpConnector.alreadyStarted")); threadName = "HttpConnector[" + port + "]"; //打開監聽 lifecycle.fireLifecycleEvent(START_EVENT, null); started = true; // Start our background thread //開啓一個後臺鏈接器線程 threadStart(); //建立處理器,並調用recyle方法將其放置到棧隊列中 while (curProcessors < minProcessors) { if ((maxProcessors > 0) && (curProcessors >= maxProcessors)) break; HttpProcessor processor = newProcessor(); recycle(processor); } }
二、鏈接器、容器之間的協做關係
2.1 容器派發socket處處理器線程
public void run() { // Loop until we receive a shutdown command //開啓循環,知道咱們得到告終束命令 while (!stopped) { // Accept the next incoming connection from the server socket Socket socket = null; try { //得到socket請求 socket = serverSocket.accept(); // 設置超時時間 if (connectionTimeout > 0) socket.setSoTimeout(connectionTimeout); //設置tcp nodelay屬性 socket.setTcpNoDelay(tcpNoDelay); } catch (AccessControlException ace) { //拋出鏈接安全錯誤信息 log("socket accept security exception", ace); continue; } catch (IOException e) { try { // If reopening fails, exit //若是再次開啓失敗,退出 synchronized (threadSync) { if (started && !stopped) log("accept error: ", e); if (!stopped) { // 關閉異常鏈接 serverSocket.close(); // 從新開啓異常鏈接 serverSocket = open(); } } // 異常處理,包括不限於祕鑰等錯誤請求 } catch (Exception ioe) { log("socket reopen, io problem: ", ioe); break; } continue; } //判斷處理器棧是否有可用處理器,沒有按規則生成,有則獲取棧中處理器 HttpProcessor processor = createProcessor(); //獲取處理器爲空,可能狀況是請求數量過多,超過了承受的最大處理器個數 if (processor == null) { try { log(sm.getString("httpConnector.noProcessor")); socket.close(); } catch (IOException e) { ; } continue; } //派發socket處處理器 processor.assign(socket); // The processor will recycle itself when it finishes } //獲取到告終束命令,通知其餘線程 synchronized (threadSync) { threadSync.notifyAll(); } }
2.2處理器接收到派發socket
synchronized void assign(Socket socket) { // d等待該處理器的其它socket處理執行完畢 while (available) { try { wait(); } catch (InterruptedException e) { } } // Store the newly available Socket and notify our thread //將新獲取的socket放置處處理器中,併發送線程通知 this.socket = socket; available = true; notifyAll(); if ((debug >= 1) && (socket != null)) log(" An incoming request is being assigned"); }
2.3 處理器接收到了socket請求,準備處理
public void run() { // Process requests until we receive a shutdown signal while (!stopped) { // Wait for the next socket to be assigned //等待鏈接器的socket請求 Socket socket = await(); if (socket == null) continue; // Process the request from this socket try { //處理socket請求 process(socket); } catch (Throwable t) { log("process.invoke", t); } // Finish up this request //處理完畢,將該processor線程歸還給Stack processors 用來處理接下來的socket請求 connector.recycle(this); } // Tell threadStop() we have shut ourselves down successfully synchronized (threadSync) { //該處理器線程退出,通知其餘processor threadSync.notifyAll(); } }
未完待續