Coin163

首页 > Tomcat连接器运行过程(源码阅读)

Tomcat连接器运行过程(源码阅读)

相关标签: 源码阅读 tomcat

2020腾讯云双十一活动,全年最低!!!(领取3500元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1073

2020阿里云双十一最低价产品入口,含代金券(新老用户有优惠),
入口地址https://www.aliyun.com/minisite/goods

相关推荐:tomcat源码分析 StandardServer初始化过程

原文:http://www.cnblogs.com/knockon/p/3330756.html ----------------------------以下为initInternal方法---------------------------- 1、调用父类org.apache.catalina.util.LifecycleMBeanBase#initInternal方法,注册MBean 2、注册本类的其它属性的MBe

:为了单纯的了解连接器运行过程,与别的组件相关部分代码被注释了,该篇文章只是简单的对重点代码进行解释,理论知识可以参考《how tomcat works》这本书,感觉还是不错的。

1.启动(这是自己写的一个简单启动代码)

private static void start() {
HttpConnector connector = new HttpConnector();
connector.start();
    }

2.HttpConnecter类中的start()方法

    public void start() {
        // Validate and update our current state
        // if (started)
        // throw new
        // LifecycleException(sm.getString("httpConnector.alreadyStarted"));
        threadName = "HttpConnector[" + port + "]";
        // lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;

        //启动当前线程
        threadStart();

        // Create the specified minimum number of processors
        while (curProcessors < minProcessors) {
            if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
                break;
            HttpProcessor processor = newProcessor();
            //将当前线程创建处理器加入处理器池中
            recycle(processor);
        }
    }

3.HttpConnecter类中threadStart()方法

private void threadStart() {

        // log(sm.getString("httpConnector.starting"));
        // 启动当前的connector的线程
        thread = new Thread(this, threadName);
        // 设置为守护线程
        thread.setDaemon(true);
        thread.start();

    }

4.HttpConnector类的run()方法

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 = serverSocket.accept();

                // 设置链接超时(假设设置为10分钟)以后,如果客户端socket和服务端socket链接以后10中以后会自动断开
                // tcp链接,默认是一支不设置超时就是一直链接的
                if (connectionTimeout > 0)
                    socket.setSoTimeout(connectionTimeout);
                // 决定是否使用nagle算法,也就是将小数据报先不发送,附加在下一个数据包后面发送过来
                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();
                            // if (debug >= 3)
                            // log("run: Reopening server socket");
                            // serverSocket = open();
                        }
                    }

                } catch (IOException ioe) {
                    log("socket reopen, io problem: ", ioe);
                    break;
                } catch (KeyStoreException kse) {
                    log("socket reopen, keystore problem: ", kse);
                    break;
                } catch (NoSuchAlgorithmException nsae) {
                    log("socket reopen, keystore algorithm problem: ", nsae);
                    break;
                } catch (CertificateException ce) {
                    log("socket reopen, certificate problem: ", ce);
                    break;
                } catch (UnrecoverableKeyException uke) {
                    log("socket reopen, unrecoverable key: ", uke);
                    break;
                } catch (KeyManagementException kme) {
                    log("socket reopen, key management problem: ", kme);
                    break;
                }

                continue;
            }

            // Hand this socket off to an appropriate processor
            // 启动完一个proccessor线程以后,先让它们处于wait状态,因为此时并没有需要处理的请求。
            HttpProcessor processor = createProcessor();
            if (processor == null) {
                try {
                    // log(sm.getString("httpConnector.noProcessor"));
                    socket.close();
                } catch (IOException e) {
                    ;
                }
                continue;
            }
            // 将tcp连接封装的socket对象分配给Processor处理
            processor.assign(socket);

            // The processor will recycle itself when it finishes
            synchronized (threadSync) {
                threadSync.notifyAll();
            }
        }
    }

5.HttpConnector类的assign()方法

synchronized void assign(Socket socket) {


            // Wait for the Processor to get the previous Socket,默认为false
            while (available) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }

            // Store the newly available Socket and notify our thread
            this.socket = socket;
            //通知processor的线程现在可以启动了
            available = true;
            //通知自己的在等待的线程可以激活了,他们会自己去竞争资源
            //因为是用当前processor的对象来进行wait的(),因此就是通知当前processor的线程运行,而不是所有
            //在等待processor线程
            notifyAll();

            if ((debug >= 1) && (socket != null))
                log(" An incoming request is being assigned");

        }

接下来看看与处理器创建相关代码,因为一个连接器中有可以有多个处理器,因此查看各个处理器创建的过程是很有必要的,这里的多个处理器采用的是处理器池是实现的,跟dbcp数据库连接池的实现方式很相似,接下来看代码

6.httpConnector中createProcessor()方法
注,其中processors的声明是这样的:

private Stack<Object> processors = new Stack<Object>();
private HttpProcessor createProcessor() {

        synchronized (processors) {
            // 池中有处理器可用
            if (processors.size() > 0) {

                return ((HttpProcessor) processors.pop());
            }
            // 如果处理器池中没有可以用的处理器,则判断当前的处理器个数(此时池中是空的)是否大于设置最大处理器个数,

            if ((maxProcessors > 0) && (curProcessors < maxProcessors)) {
                // 没有则创建
                return (newProcessor());
            } else {
                // 如果处理器最大个数被设置为-1,则要多少个处理器就创建多少个,不受限制
                if (maxProcessors < 0) {

                    return (newProcessor());

                } else {

                    return (null);
                }
            }
        }
    }

7.httpConnector中newProcessor()方法

private HttpProcessor newProcessor() {

        // 当创建一个处理器,则当前处理器标记加1,给改处理器设置了个名字,线程也是这么做的
        HttpProcessor processor = new HttpProcessor(this, curProcessors++);
        if (processor instanceof Lifecycle) {
            try {
                // 在HttpProcessor类中的start方法里启动processor线程(没创建一个处理器就马上启动,但是启动万以后并没有让processor的run方法马上执行,而是出于wait状态)
                ((Lifecycle) processor).start();
            } catch (Exception e) {
                log("newProcessor", e);
                return (null);
            }
        }
        created.addElement(processor);
        return (processor);

    }

接下来我们看看HttpProcessor中相关代码
1.HttpProcessor中start()方法

// 基本上都是用在start方法中启动自己的线程的。
    public void start() // throws LifecycleException
    {

        // if (started)
        // throw new LifecycleException
        // (sm.getString("httpProcessor.alreadyStarted"));
        // lifecycle.fireLifecycleEvent(START_EVENT, null);
        // started = true;

        threadStart();

    }

2.HttpProcessor中start()方法

 private void threadStart() {

            //log(sm.getString("httpProcessor.starting"));

            thread = new Thread(this, threadName);
            //设置为守护线程,因为tomcat是为web应用程序服务的,所以他的线程一般都是守护线程
            //同时,在守护线程中创建的线程即使不setDaemon,也是守护线程
            thread.setDaemon(true);
            //开启processor中的run方法。
            thread.start();

            if (debug >= 1)
                log(" Background thread has been started");

        }

3.HttpProcessor中run()方法

public void run() {

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

            //当前线程等待下一个socket来以后激活所有的等等的线程(就是处理器创建以后不马上执行完,而是出于wait状态等待socket来以后并被别的线程激活)
            Socket socket = await();
            if (socket == null)
                continue;

            // Process the request from this socket
            try {
            //该方法就是处理socket,用户解析http头,创建request和response对象(以后会单独详细讲)
                process(socket);
            } catch (Throwable t) {
                log("process.invoke", t);
            }

            // Finish up this request
            connector.recycle(this);
 // Tell threadStop() we have shut ourselves down successfully
        synchronized (threadSync) {
            threadSync.notifyAll();
        }
        }

4.HttpProcessor中await()方法

  private synchronized Socket await() {

        // Wait for the Connector to provide a new Socket
        while (!available) {
            try {
            //就是调用当前对象的wait()方法
                wait();
            } catch (InterruptedException e) {
            }
        }
    }

5.HttpProcessor中process()方法

public void process(Socket socket)
{
//该方法是处理http头和内容的,接下来会详细讲
}

到此,tomcat中连接器的运行过程基本结束了,怎么处理socket会在之后详细讲

原文

注:为了单纯的了解连接器运行过程,与别的组件相关部分代码被注释了,该篇文章只是简单的对重点代码进行解释,理论知识可以参考《how tomcat works》这本书,感觉还是不错的。 1.启动(这是自

------分隔线----------------------------