上文说了简单的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(); } }
未完待续