Tomcat6.0连接器源码分析

简介:

首先看BIO模式。

Server.conf配置连接器如下:
<Connector port="8081" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
protocol设定为"HTTP/1.1",这里指org.apache.coyote.http11.Http11Protocol,
相应的转换代码在Connector类里:
 
 
  1. public void setProtocol(String protocol) {  
  2.         if (AprLifecycleListener.isAprAvailable()) {  
  3.             if ("HTTP/1.1".equals(protocol)) {  
  4.                 setProtocolHandlerClassName  
  5.                     ("org.apache.coyote.http11.Http11AprProtocol");  
  6.             } else if ("AJP/1.3".equals(protocol)) {  
  7.                 setProtocolHandlerClassName  
  8.                     ("org.apache.coyote.ajp.AjpAprProtocol");  
  9.             } else if (protocol != null) {  
  10.                 setProtocolHandlerClassName(protocol);  
  11.             } else {  
  12.                 setProtocolHandlerClassName  
  13.                     ("org.apache.coyote.http11.Http11AprProtocol");  
  14.             }  
  15.         } else {  
  16.             if ("HTTP/1.1".equals(protocol)) {  
  17.                 setProtocolHandlerClassName  
  18.                     ("org.apache.coyote.http11.Http11Protocol");  
  19.             } else if ("AJP/1.3".equals(protocol)) {  
  20.                 setProtocolHandlerClassName  
  21.                     ("org.apache.jk.server.JkCoyoteHandler");  
  22.             } else if (protocol != null) {  
  23.                 setProtocolHandlerClassName(protocol);  
  24.             }  
  25.         }  
我们这里没有apr 也没有ajp.所以ProtocolHandlerClassName就是org.apache.coyote.http11.Http11Protocol,Http11Protocol在init里,会初始化JioEndpoint。
以后的工作主要由JioEndpoint来处理请求连接,来看看JioEndpoint的init方法:
 
  
 
  1. public void init()  
  2.        throws Exception {  
  3.  
  4.        if (initialized)  
  5.            return;  
  6.          
  7.        // Initialize thread count defaults for acceptor  
  8.        if (acceptorThreadCount == 0) {  
  9.            acceptorThreadCount = 1;  
  10.        }  
  11.        if (serverSocketFactory == null) {  
  12.            serverSocketFactory = ServerSocketFactory.getDefault();  
  13.        }  
  14.        if (serverSocket == null) {  
  15.            try {  
  16.                if (address == null) {  
  17.                    serverSocket = serverSocketFactory.createSocket(port, backlog);  
  18.                } else {  
  19.                    serverSocket = serverSocketFactory.createSocket(port, backlog, address);  
  20.                }  
  21.            } catch (BindException orig) {  
  22.                String msg;  
  23.                if (address == null)  
  24.                    msg = orig.getMessage() + " <null>:" + port;  
  25.                else 
  26.                    msg = orig.getMessage() + " " +  
  27.                            address.toString() + ":" + port;  
  28.                BindException be = new BindException(msg);  
  29.                be.initCause(orig);  
  30.                throw be;  
  31.            }  
  32.        }  
  33.        //if( serverTimeout >= 0 )  
  34.        //    serverSocket.setSoTimeout( serverTimeout );  
  35.          
  36.        initialized = true;  
  37.          
主要目的就是创建ServerSocket. 有了服务端的listener.
 
Http11Protocol启动的时候,相应的启动JioEndpoint.
 
JioEndpoint 的start方法:
 
 
  1. public void start()  
  2.         throws Exception {  
  3.         // Initialize socket if not done before  
  4.         if (!initialized) {  
  5.            init();  
  6.         }  
  7.         if (!running) {  
  8.             running = true;  
  9.             paused = false;  
  10.    
  11.             // Create worker collection  
  12.             if (executor == null) {//目前executor都为空,非空的下一节会讨论  
  13.                 workers = new WorkerStack(maxThreads);//①.创建工作线程。  
  14.             }  
  15.    
  16.             // Start acceptor threads  
  17.             for (int i = 0; i < acceptorThreadCount; i++) {  
  18.                 Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i);  
  19.                 acceptorThread.setPriority(threadPriority);  
  20.                 acceptorThread.setDaemon(daemon);  
  21.                 acceptorThread.start(); // 2.启动接收线程.  
  22.             }  
  23.         }  
  24.     }  
在①处,WorkerStack模拟一个栈,里面用数组存储工作线程(Tomcat这帮人就喜欢用数组)。用来处理请求过来的socket.
在2处,启动一个接收线程,接收请求连接。
 
Acceptor代码如下:
 
 
  1.  /**  
  2.      * Server socket acceptor thread.  
  3.      */ 
  4.     protected class Acceptor implements Runnable {  
  5.         /**  
  6.          * The background thread that listens for incoming TCP/IP connections and  
  7.          * hands them off to an appropriate processor.  
  8.          */ 
  9.         public void run() {  
  10.    
  11.             // Loop until we receive a shutdown command  
  12.             while (running) {  
  13.    
  14.                 // Loop if endpoint is paused  
  15.                 while (paused) {  
  16.                     try {  
  17.                         Thread.sleep(1000);  
  18.                     } catch (InterruptedException e) {  
  19.                         // Ignore  
  20.                     }  
  21.                 }  
  22.    
  23.                 // Accept the next incoming connection from the server socket  
  24.                 try {  
  25.                     Socket socket = serverSocketFactory.acceptSocket(serverSocket);  
  26.                     serverSocketFactory.initSocket(socket);  
  27.                     // Hand this socket off to an appropriate processor  
  28.                     if (!processSocket(socket)) {  
  29.                         // Close socket right away  
  30.                         try {  
  31.                             socket.close();  
  32.                         } catch (IOException e) {  
  33.                             // Ignore  
  34.                         }  
  35.                     }  
  36.                 }catch ( IOException x ) {  
  37.                     if ( running ) log.error(sm.getString("endpoint.accept.fail"), x);  
  38.                 } catch (Throwable t) {  
  39.                     log.error(sm.getString("endpoint.accept.fail"), t);  
  40.                 }  
  41.    
  42.                 // The processor will recycle itself when it finishes  
  43.    
  44.             }  
  45.    
  46.         }  
  47.     }  
  48. serverSocketFactory.acceptSocket用init方法里创建的severSocket accept一个连接Socket。然后processSocket(socket).  
  49. 下面看processSocke(socket)方法:  
  50.    
  51. protected boolean processSocket(Socket socket) {  
  52.         try {  
  53.             if (executor == null) { //目前executor都为空。  
  54.                 getWorkerThread().assign(socket);  
  55.             } else {  
  56.                 executor.execute(new SocketProcessor(socket));  
  57.             }  
  58.         } catch (Throwable t) {  
  59.             // This means we got an OOM or similar creating a thread, or that  
  60.             // the pool and its queue are full  
  61.             log.error(sm.getString("endpoint.process.fail"), t);  
  62.             return false;  
  63.         }  
  64.         return true;  
  65.     }  
getWorkerThread()方法是从刚才创建的工作线程栈WorkerStack中取得一个工作线程。
这段代码很简单,就不说了,有兴趣看一下Tomcat的源代码(Class:JioEndpoint).
 
我们看一下工作线程类Worker吗。
 
  1. protected class Worker implements Runnable {  
  2.    
  3.         protected Thread thread = null;  
  4.         protected boolean available = false;  
  5.         protected Socket socket = null;  
  6.    
  7.       /**  
  8.          * Process an incoming TCP/IP connection on the specified socket. Any  
  9.          * exception that occurs during processing must be logged and swallowed.  
  10.          * <b>NOTE</b>: This method is called from our Connector's thread. We  
  11.          * must assign it to our own thread so that multiple simultaneous  
  12.          * requests can be handled.  
  13.          *  
  14.          * @param socket TCP socket to process  
  15.          */ 
  16.         synchronized void assign(Socket socket) {  
  17.    
  18.             // Wait for the Processor to get the previous Socket  
  19.             while (available) {  
  20.                 try {  
  21.                     wait();  
  22.                 } catch (InterruptedException e) {  
  23.                 }  
  24.             }  
  25.             // Store the newly available Socket and notify our thread  
  26.             this.socket = socket;  
  27.             available = true;  
  28.             notifyAll();  
  29.    
  30.         }  
  31.    
  32.           
  33.         /**  
  34.          * Await a newly assigned Socket from our Connector, or <code>null</code>  
  35.          * if we are supposed to shut down.  
  36.          */ 
  37.        private synchronized Socket await() {  
  38.             // Wait for the Connector to provide a new Socket  
  39.             while (!available) {  
  40.                 try {  
  41.                     wait();  
  42.                 } catch (InterruptedException e) {  
  43.                 }  
  44.             }  
  45.    
  46.             // Notify the Connector that we have received this Socket  
  47.             Socket socket = this.socket;  
  48.             available = false;  
  49.             notifyAll();  
  50.    
  51.             return (socket);  
  52.    
  53.         }  
  54.         /**  
  55.          * The background thread that listens for incoming TCP/IP connections and  
  56.          * hands them off to an appropriate processor.  
  57.          */ 
  58.         public void run() {  
  59.    
  60.             // Process requests until we receive a shutdown signal  
  61.             while (running) {  
  62.    
  63.                 // Wait for the next socket to be assigned  
  64.                 Socket socket = await();  
  65.                 if (socket == null)  
  66.                     continue;  
  67.    
  68.                 // Process the request from this socket  
  69.                 if (!setSocketOptions(socket) || !handler.process(socket)) {  
  70.                     // Close socket  
  71.                     try {  
  72.                         socket.close();  
  73.                     } catch (IOException e) {  
  74.                     }  
  75.                 }  
  76.    
  77.                 // Finish up this request  
  78.                 socket = null;  
  79.                 recycleWorkerThread(this);  
  80.    
  81.             }  
  82.    
  83.         }  
  84.        /**  
  85.          * Start the background processing thread.  
  86.          */ 
  87.         public void start() {  
  88.             thread = new Thread(this);  
  89.             thread.setName(getName() + "-" + (++curThreads));  
  90.             thread.setDaemon(true);  
  91.             thread.start();  
  92.         }  
  93.     }  
首行看一下刚刚被调用的assign方法,Worker类通过available互斥。Available可理解为是否还有现成的Socket绑定在这个工作线程上,true表示有。Assign首先判断Available,如果有可用socket,即Available为true,则wait直到被唤醒。  This method is called from our Connector's thread.告诉我们该方法由连接器线程调用。那么工作线程自己呢。看run方法,调用了await,按照上面的理解,如果没有可用的socket,即Available为false,则wait直到被唤醒。如果为true,刚马上拿走这个socket.并把Available设为false.就可以有新的Socket放进来了。
 
但这里有点问题,从WorkerStack栈出取出的Worker或者新建的Worker,Available肯定都为false.那么assign方法的 while (available)循环就没有必要了。不清楚为什么作者这么写。
 
获得Socket之后交由handler去处理,这里的handler就
是Http11Protocol$Http11ConnectionHandler,处理流程,以会再讨论。

本文转自 anranran 51CTO博客,原文链接:http://blog.51cto.com/guojuanjun/538310

目录
打赏
0
0
0
0
351
分享
相关文章
优雅上下线之如何安全的关闭Tomcat持久连接
优雅上下线之如何安全的关闭Tomcat持久连接
502 3
Tomcat AJP连接器配置secretRequired=“true“,但是属性secret确实空或者空字符串,这样的组合是无效的。
Tomcat AJP连接器配置secretRequired=“true“,但是属性secret确实空或者空字符串,这样的组合是无效的。
解决在访问tomcat时出现连接失败,Firefox 无法建立到 localhost:8080 服务器的连接的问题~
解决在访问tomcat时出现连接失败,Firefox 无法建立到 localhost:8080 服务器的连接的问题~
388 0
Spring Boot整合Tomcat底层源码分析
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置和起步依赖等特性,大大简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是其与Tomcat的整合。
253 1
【Tomcat源码分析】从零开始理解 HTTP 请求处理 (第一篇)
本文详细解析了Tomcat架构中复杂的`Connector`组件。作为客户端与服务器间沟通的桥梁,`Connector`负责接收请求、封装为`Request`和`Response`对象,并传递给`Container`处理。文章通过四个关键问题逐步剖析了`Connector`的工作原理,并深入探讨了其构造方法、`init()`与`start()`方法。通过分析`ProtocolHandler`、`Endpoint`等核心组件,揭示了`Connector`初始化及启动的全过程。本文适合希望深入了解Tomcat内部机制的读者。欢迎关注并点赞,持续更新中。如有问题,可搜索【码上遇见你】交流。
【Tomcat源码分析】从零开始理解 HTTP 请求处理 (第一篇)
【Tomcat源码分析】启动过程深度解析 (二)
本文深入探讨了Tomcat启动Web应用的过程,重点解析了其加载ServletContextListener及Servlet的机制。文章从Bootstrap反射调用Catalina的start方法开始,逐步介绍了StandardServer、StandardService、StandardEngine、StandardHost、StandardContext和StandardWrapper的启动流程。每个组件通过Lifecycle接口协调启动,子容器逐层启动,直至整个服务器完全启动。此外,还详细分析了Pipeline及其Valve组件的作用,展示了Tomcat内部组件间的协作机制。
【Tomcat源码分析】启动过程深度解析 (二)
【Tomcat源码分析 】"深入探索:Tomcat 类加载机制揭秘"
本文详细介绍了Java类加载机制及其在Tomcat中的应用。首先回顾了Java默认的类加载器,包括启动类加载器、扩展类加载器和应用程序类加载器,并解释了双亲委派模型的工作原理及其重要性。接着,文章分析了Tomcat为何不能使用默认类加载机制,因为它需要解决多个应用程序共存时的类库版本冲突、资源共享、类库隔离及JSP文件热更新等问题。最后,详细展示了Tomcat独特的类加载器设计,包括Common、Catalina、Shared、WebApp和Jsp类加载器,确保了系统的稳定性和安全性。通过这种设计,Tomcat实现了不同应用程序间的类库隔离与共享,同时支持JSP文件的热插拔。
【Tomcat源码分析 】"深入探索:Tomcat 类加载机制揭秘"
【Tomcat源码分析】Pipeline 与 Valve 的秘密花园
本文深入剖析了Tomcat中的Pipeline和Valve组件。Valve作为请求处理链中的核心组件,通过接口定义了关键方法;ValveBase为其基类,提供了通用实现。Pipeline则作为Valve容器,通过首尾相连的Valve链完成业务处理。StandardPipeline实现了Pipeline接口,提供了详细的Valve管理逻辑。通过对代码的详细分析,揭示了模板方法模式和责任链模式的应用,展示了系统的扩展性和模块化设计。
【Tomcat源码分析】Pipeline 与 Valve 的秘密花园
【Tomcat源码分析】生命周期机制 Lifecycle
Tomcat内部通过各种组件协同工作,构建了一个复杂的Web服务器架构。其中,`Lifecycle`机制作为核心,管理组件从创建到销毁的整个生命周期。本文详细解析了Lifecycle的工作原理及其方法,如初始化、启动、停止和销毁等关键步骤,并展示了LifecycleBase类如何通过状态机和模板模式实现这一过程。通过深入理解Lifecycle,我们可以更好地掌握组件生命周期管理,提升系统设计能力。欢迎关注【码上遇见你】获取更多信息,或搜索【AI贝塔】体验免费的Chat GPT。希望本章内容对你有所帮助。
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问