`
anranran
  • 浏览: 29074 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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类里:
public void setProtocol(String protocol) {
        if (AprLifecycleListener.isAprAvailable()) {
            if ("HTTP/1.1".equals(protocol)) {
                setProtocolHandlerClassName
                    ("org.apache.coyote.http11.Http11AprProtocol");
            } else if ("AJP/1.3".equals(protocol)) {
                setProtocolHandlerClassName
                    ("org.apache.coyote.ajp.AjpAprProtocol");
            } else if (protocol != null) {
                setProtocolHandlerClassName(protocol);
            } else {
                setProtocolHandlerClassName
                    ("org.apache.coyote.http11.Http11AprProtocol");
            }
        } else {
            if ("HTTP/1.1".equals(protocol)) {
                setProtocolHandlerClassName
                    ("org.apache.coyote.http11.Http11Protocol");
            } else if ("AJP/1.3".equals(protocol)) {
                setProtocolHandlerClassName
                    ("org.apache.jk.server.JkCoyoteHandler");
            } else if (protocol != null) {
                setProtocolHandlerClassName(protocol);
            }
        }
}

我们这里没有apr 也没有ajp.所以ProtocolHandlerClassName就是org.apache.coyote.http11.Http11Protocol,Http11Protocol在init里,会初始化JioEndpoint。
以后的工作主要由JioEndpoint来处理请求连接,来看看JioEndpoint的init方法:
   public void init()
        throws Exception {

        if (initialized)
            return;
        
        // Initialize thread count defaults for acceptor
        if (acceptorThreadCount == 0) {
            acceptorThreadCount = 1;
        }
        if (serverSocketFactory == null) {
            serverSocketFactory = ServerSocketFactory.getDefault();
        }
        if (serverSocket == null) {
            try {
                if (address == null) {
                    serverSocket = serverSocketFactory.createSocket(port, backlog);
                } else {
                    serverSocket = serverSocketFactory.createSocket(port, backlog, address);
                }
            } catch (BindException orig) {
                String msg;
                if (address == null)
                    msg = orig.getMessage() + " <null>:" + port;
                else
                    msg = orig.getMessage() + " " +
                            address.toString() + ":" + port;
                BindException be = new BindException(msg);
                be.initCause(orig);
                throw be;
            }
        }
        //if( serverTimeout >= 0 )
        //    serverSocket.setSoTimeout( serverTimeout );
        
        initialized = true;
        
}

主要目的就是创建ServerSocket,用于接收连接请求(废话,ServerSocket谁不知道)。

连接器启动时,会启动Http11Protocol,相应的启动JioEndpoint.

JioEndpoint 的start方法:

public void start()
        throws Exception {
        // Initialize socket if not done before
        if (!initialized) {
           init();
        }
        if (!running) {
            running = true;
            paused = false;

            // Create worker collection
            if (executor == null) {//目前executor都为空,非空的下一节会讨论
                workers = new WorkerStack(maxThreads);//①.创建工作线程。
            }

            // Start acceptor threads
            for (int i = 0; i < acceptorThreadCount; i++) {
                Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i);
                acceptorThread.setPriority(threadPriority);
                acceptorThread.setDaemon(daemon);
                acceptorThread.start(); //②.启动接收线程.
            }
        }
    }

在①处,WorkerStack模拟一个栈,里面用数组存储工作线程(Tomcat这帮人就喜欢用数组),用来处理请求过来的socket.
在②处,启动一个接收线程,接收请求连接。

Acceptor代码如下:
  /**
     * Server socket acceptor thread.
     */
    protected class Acceptor implements Runnable {
        /**
         * The background thread that listens for incoming TCP/IP connections and
         * hands them off to an appropriate processor.
         */
        public void run() {

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

                // Loop if endpoint is paused
                while (paused) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }

                // Accept the next incoming connection from the server socket
                try {
                    Socket socket = serverSocketFactory.acceptSocket(serverSocket);
                    serverSocketFactory.initSocket(socket);
                    // Hand this socket off to an appropriate processor
                    if (!processSocket(socket)) {
                        // Close socket right away
                        try {
                            socket.close();
                        } catch (IOException e) {
                            // Ignore
                        }
                    }
                }catch ( IOException x ) {
                    if ( running ) log.error(sm.getString("endpoint.accept.fail"), x);
                } catch (Throwable t) {
                    log.error(sm.getString("endpoint.accept.fail"), t);
                }

                // The processor will recycle itself when it finishes

            }

        }
    }

serverSocketFactory.acceptSocket用init方法里创建的severSocket accept一个连接Socket。然后processSocket(socket).
下面看processSocke(socket)方法:
protected boolean processSocket(Socket socket) {
        try {
            if (executor == null) { //目前executor都为空。
                getWorkerThread().assign(socket);
            } else {
                executor.execute(new SocketProcessor(socket));
            }
        } catch (Throwable 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;
    }

getWorkerThread()方法是从刚才创建的工作线程栈WorkerStack中取得一个工作线程。
这段代码很简单,就不说了,有兴趣看一下Tomcat的源代码(Class:JioEndpoint).

我们看一下工作线程类Worker吗。
protected class Worker implements Runnable {

        protected Thread thread = null;
        protected boolean available = false;
        protected Socket socket = null;

      /**
         * Process an incoming TCP/IP connection on the specified socket.  Any
         * exception that occurs during processing must be logged and swallowed.
         * <b>NOTE</b>:  This method is called from our Connector's thread.  We
         * must assign it to our own thread so that multiple simultaneous
         * requests can be handled.
         *
         * @param socket TCP socket to process
         */
        synchronized void assign(Socket socket) {

            // Wait for the Processor to get the previous Socket
            while (available) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
            // Store the newly available Socket and notify our thread
            this.socket = socket;
            available = true;
            notifyAll();

        }

        
        /**
         * Await a newly assigned Socket from our Connector, or <code>null</code>
         * if we are supposed to shut down.
         */
       private synchronized Socket await() {
            // Wait for the Connector to provide a new Socket
            while (!available) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }

            // Notify the Connector that we have received this Socket
            Socket socket = this.socket;
            available = false;
            notifyAll();

            return (socket);

        }
        /**
         * The background thread that listens for incoming TCP/IP connections and
         * hands them off to an appropriate processor.
         */
        public void run() {

            // Process requests until we receive a shutdown signal
            while (running) {

                // Wait for the next socket to be assigned
                Socket socket = await();
                if (socket == null)
                    continue;

                // Process the request from this socket
                if (!setSocketOptions(socket) || !handler.process(socket)) {
                    // Close socket
                    try {
                        socket.close();
                    } catch (IOException e) {
                    }
                }

                // Finish up this request
                socket = null;
                recycleWorkerThread(this);

            }

        }
       /**
         * Start the background processing thread.
         */
        public void start() {
            thread = new Thread(this);
            thread.setName(getName() + "-" + (++curThreads));
            thread.setDaemon(true);
            thread.start();
        }
    }

首行看一下刚刚被调用的assign方法,Worker类通过available实现互斥。Available可理解为是否还有现成的Socket绑定在这个工作线程上,true表示有。Assign首先判断Available,如果有可用socket,即Available为true,说明前一个socket还没有开始处理,则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,处理流程,以会再讨论。
分享到:
评论
1 楼 sodmewuhan 2012-12-06  
good job!

相关推荐

    Tomcat 6.0 -- 9.0 及其源码

    《深入理解Tomcat 6.0 -- 9.0及源码分析》 Tomcat,作为Apache软件基金会的开源项目,是Java Servlet和JavaServer Pages(JSP)的开源Web应用服务器,也是世界上最受欢迎的轻量级应用服务器之一。本文将深入探讨...

    tomcat6.0源码,可直接导入eclipse运行

    通过阅读和分析源码,你可以了解Tomcat如何加载web应用程序,如何处理请求,以及如何管理线程池和连接器。同时,也可以深入研究JSP编译过程、会话管理、安全性和性能优化等方面。 对于Eclipse用户,利用其强大的...

    Tomcat6.0的源码包

    【标题】"Tomcat6.0的源码包"提供了对Apache Tomcat 6.0这一版本的服务器软件的内部工作原理的深入了解。Tomcat是一款开源的Java Servlet容器,广泛用于部署Java Web应用程序。它是Java EE(现称为Jakarta EE)的一...

    tomcat6.0源码

    在Tomcat 6.0中,主要有两个连接器:BioC(基于Java BIO的连接器)和AprC(使用Apache Portable Runtime库的连接器)。源码分析可以帮助理解连接器如何接收和处理HTTP请求,并返回响应。 4. **JNDI服务** Tomcat内...

    tomcat源码基于6.0

    总结,Tomcat 6.0源码分析是一个深入了解Java Web服务器运行机制的过程,这不仅有助于我们理解Web服务器的工作原理,还能帮助我们优化应用性能、排查问题,甚至为开发自定义服务器提供基础。通过深入研究`apache-...

    tomcat6.0源码及编译依赖项(可编译)

    4. **连接器与协议处理**:Coyote是Tomcat处理HTTP请求的组件,它支持多种协议,如HTTP/1.1。源码中可以研究Coyote如何接收和解析HTTP请求,以及如何生成响应。 5. **JSP与Servlet**:Jasper组件负责将JSP文件转换...

    tomcat6.0

    标题 "Tomcat6.0" 暗示我们即将探讨的是Apache Tomcat 6.0版本,这是一个流行的开源Java Servlet容器,用于部署和运行Java Web应用程序。Tomcat是基于Java Servlet和JavaServer Pages (JSP) 技术的,它是Apache软件...

    tomcat 6.0源码

    通过分析Tomcat 6.0的源码,开发者不仅可以学习到Servlet和JSP的运行机制,还可以了解到Web服务器的设计模式、性能优化以及安全性控制等方面的知识。这对于提升Java Web开发技能和理解服务器底层运作至关重要。

    myeclipse+tomcat6.0+struts2开发的登录程序

    标题 "myeclipse+tomcat6.0+struts2开发的登录程序" 提供了我们正在探讨的技术栈,这是一个使用MyEclipse作为集成开发环境(IDE),Tomcat 6.0作为应用服务器,以及Struts2作为MVC框架来构建的登录应用程序。...

    Tomcat6源码下载

    4. **连接器与协议处理**:Coyote作为Tomcat的连接器,负责监听端口,接收并解析HTTP请求。它支持多种协议处理器,如AJP(Apache JServ Protocol)和HTTP/1.1,这些处理器负责与客户端进行数据交换。 5. **线程池...

    Apache-tomcat6

    Tomcat6.0还提供了更好的可扩展性,通过模块化的设计,可以方便地添加或移除特定的功能模块,如连接器(Connector)和Valve(阀门)。Valve是Tomcat处理请求生命周期的关键组件,通过自定义Valve,开发者可以实现...

    Tomcat6.0.41源代码,可直接导入Eclipse

    Tomcat由几个核心组件构成,包括Catalina(Servlet容器)、Jasper(JSP引擎)、 Coyote(HTTP连接器)和Commons组件。Catalina是Tomcat的核心,负责处理Servlet规范;Jasper解析并编译JSP页面为Servlet;Coyote处理...

    apache-tomcat-7.0.62-src和apache-tomcat-6.0.39-src的源码

    4. **连接器(Connector)与引擎(Engine)**:Tomcat的核心架构包括Connector和Container,其中Connector负责接收和发送HTTP请求,Container负责处理请求。在`conf/server.xml`中,你可以配置这些组件。 5. **部署...

    基于MyEclipse6.0的SSH整合(说明+源码)

    6. **源码分析**:压缩包中的源码可能包含以下部分:Struts的Action和ActionForm类,Spring的Service和DAO类,以及Hibernate的实体类和映射文件。这些源码提供了实际的业务处理和数据访问实现,通过阅读和理解这些...

    Apache-Tomcat_Src_Code

    1. **Tomcat架构**:Tomcat的核心架构分为几个主要组件,包括Catalina(核心Servlet容器)、Jasper(JSP编译器)、 Coyote(HTTP/HTTPS连接器)和Juli(日志系统)。每个组件都有其特定职责,协同工作以处理Web请求...

    Roller初体验

    2. **源码分析**:对于技术爱好者,Roller的源码提供了一个了解Web应用程序开发和Java Servlet技术的好机会。通过阅读源码,可以学习到MVC(模型-视图-控制器)设计模式的实现,以及Spring框架、Hibernate持久层框架...

    JSTL应用项目源代码

    通过分析这个项目源码,学习者可以深入理解如何将JSTL标签与Servlet、JavaBean结合,构建动态Web应用程序。同时,项目在Tomcat 6.0上的成功运行,意味着它遵循了Java EE的规范,兼容旧版本的服务器,有助于学习者...

Global site tag (gtag.js) - Google Analytics