`

Tomcat接收请求

 
阅读更多

 

1. 启动Tomcat后, 在哪里接收Request?

      启动Tomcat时,部署完webapp 后,就会启动connector ,启动这个连接器,也就意味着会启动一个线程来接收请求,

   具体涉及的类:

    Http11Protocol

     org.apach.tomcat.uitl.net ,

    JIoEndPoint , WorkStack (pool), Acceptor(Runnable) 

 

  首先,启动Http11Protocol会调用JIoEndpoint中的start();JIO会new监听器线程,监控连接;

 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) {
                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();
            }
        }
    }

 Acceptor(实现Runnable接口) 的 run() :启动http11Protocol ,就会阻塞在acceptSocket()上,直到有连接传入,得到Socket , 传递给Processor

   

 /**
         * The background thread that listens for incoming TCP/IP connections and
         * hands them off to an appropriate processor.
         * 监控连接,并把他们交给processor处理
         */
        public void run() {
            // Loop until we receive a shutdown command
            // 只要不是shutdown 命令 他就一直在运行 等候请求传入
            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)) { // 处理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
            }
        }
    }

 processSocket() : 取得线程,处理Socket

 /**
     * Process given socket.
     */
    protected boolean processSocket(Socket socket) {
        try {
            if (executor == null) { // exector是线程池
                getWorkerThread().assign(socket); 
            } else {
                executor.execute(new SocketProcessor(socket));// SocketProcess 实现了Runnable接口 ,process处理!
            }
        } 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;
    }
    

   可能你会举得到这里,如果不通过线程池处理,那么是怎么把request传递给servlet的了?

   通过分析下面的源码,好像getWorkThread().assign(socket) 并没有调用处理socket的方法?

    注意createWorkThread()中的“newWorkerThread() ” , 通过这个方法,我们会创建一个线程,并且会启动,Work类的源代码 它是实现了Runnable接口的!

   所以,总结Tomcat接收一个请求的过程 :

     Tomcat启动,会启动一个Acceptor线程来监听请求 , 请求传入了时,得到相应的Socket,然后通过workStack 或者 Executor的方式,产生一个新的线程来处理,

     在通过workStack 产生线程到处理的过程 : getWorkerThread() 调用createWorkerThread() 调用 newWorkerThread会产生一个Work thread , 并且start,但是

     因为socket = await() , avaliable = false , 会阻塞,通过调用 assign() , 使得available = true 把最新的socket传递进去, run()方法运行,处理socket , 这就是assign()的作用。

     但是 , 为什么要这么做了,直接new 出线程,然后run就是,就像executor一样!为什么这中间要添加这些额外的操作了?

       为了保证线程得到的是最新的socket!!

 newWorkerThread() :

 

 /**
     * Create and return a new processor suitable for processing HTTP
     * requests and returning the corresponding responses.
     */
    protected Worker newWorkerThread() {

        Worker workerThread = new Worker();
        workerThread.start(); //注意这里!!!!
        return (workerThread);

    }

  

getWrokThread() : // 不通过线程池的方式取得线程,将线程放在一个workStack中

  

 /**
     * Return a new worker thread, and block while to worker is available.
     */
    protected Worker getWorkerThread() {
        // Allocate a new worker thread
        synchronized (workers) { // 注意同步
            Worker workerThread;
            while ((workerThread = createWorkerThread()) == null) {
                try {
                    workers.wait(); // 如果不能取的线程,wait,因为你在server.xml中配置了maxThread;
                } catch (InterruptedException e) {
                    // Ignore
                }
            }
            return workerThread;
        }
    }

  

Work内部类: // 一个处理rquest的线程就是一个worker!

   里面两个特别重要的方法,assign()  和 await() 都是同步

   assgin 传递最新的socket!

   而 await 则是在等候最新的socket!

 protected class Worker implements Runnable {
        protected Thread thread = null;
        protected boolean available = false;
        protected Socket socket = null;
        // 将availabe 置为 true , 并唤醒所有等待的线程我知道了,assign的作用就是把最新的socket传递进来
        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();
        }
// 等候最新的socket
        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;  // 将available置为false!
            notifyAll();
            return (socket);
        }

// run方法
        public void run() {
            // Process requests until we receive a shutdown signal
            while (running) {
                // Wait for the next socket to be assigned
                Socket socket = await(); // 调用这个方法时,除非调用assign()方法使的available为true,否则就会一直等待!而且现在锁已经加上来了,其他线程是不能够进来了!
                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);
            }
        }

        public void start() {
            thread = new Thread(this); 
            thread.setName(getName() + "-" + (++curThreads));
            thread.setDaemon(true);
            thread.start();
        }
    }

  

createWorkThread() ; 创建一个新的线程,调用newWorkerThread() 启动线程

/**
     * Create (or allocate) and return an available processor for use in
     * processing a specific HTTP request, if possible.  If the maximum
     * allowed processors have already been created and are in use, return
     * <code>null</code> instead.
     */
    protected Worker createWorkerThread() {

        synchronized (workers) {
            if (workers.size() > 0) { // 线程栈,可用的线程
                curThreadsBusy++;
                return workers.pop();
            }
            if ((maxThreads > 0) && (curThreads < maxThreads)) {
                curThreadsBusy++;
                if (curThreadsBusy == maxThreads) {
                    log.info(sm.getString("endpoint.info.maxThreads",
                            Integer.toString(maxThreads), address,
                            Integer.toString(port)));
                }
                return (newWorkerThread()); // 注意这个方法!!
            } else {
                if (maxThreads < 0) {
                    curThreadsBusy++;
                    return (newWorkerThread());
                } else {
                    return (null);
                }
            }
        }

    }

 

 

 SocketProcess的Run() :// 处理socket ,

public void run() {
            // Process the request from this socket
            if (!setSocketOptions(socket) || !handler.process(socket)) { // handler 处理socket 通过这个方法就会将request传递给servlet
                // Close socket
                try {
                    socket.close();
                } catch (IOException e) {
                }
            }
            // Finish up this request
            socket = null;
        }

  2. 接收请求后,是怎么传递给相应的servlet处理的?

     通过调用org.apache.coyote.http11.http11Protocol.process(socket) 方法!!

分享到:
评论

相关推荐

    tomcat 分配请求之——socket获取请求

    对于每个接收到的请求,Tomcat会从线程池中取出一个空闲线程来处理。线程会读取Socket中的剩余数据,解析请求,执行相应的Servlet或JSP,然后将结果写回Socket,最后关闭Socket连接。在这个过程中,线程池管理着线程...

    apache-tomcat-8.0.3

    当用户通过浏览器发送HTTP请求到运行Tomcat的服务器时,Tomcat接收请求并转发给相应的Servlet。Servlet处理请求后,生成响应内容,再由Tomcat将其转换为HTTP响应,最终返回给客户端。 四、Tomcat的目录结构 在解压...

    解析Tomcat处理请求的类Connector<三>

    `Connector`是Tomcat与外部世界交互的关键桥梁,负责接收并转发HTTP请求到内部的Servlet容器进行处理。 首先,我们来理解`Connector`的作用。`Connector`是Tomcat的Catalina核心模块的一部分,它通过一个特定的协议...

    Tomcat7优化.docx

    Connector是Tomcat接收请求的入口,每个Connector都有自己的监听端口。配置HTTP和AJP Connector,关注`maxThreads`、`minSpareThreads`等属性,以适应不同类型的请求负载。 **JVM参数优化** 1. **JVM内存模型** ...

    tomcat6.0 tomcat6.0

    6. **连接器配置**:调整Connector元素可以改变Tomcat接收请求的方式,如设置端口、协议(HTTP/HTTPS)、最大连接数等。 7. **虚拟主机**:通过在server.xml中添加Host元素,可以配置多个虚拟主机,每个主机有自己...

    tomcat的简单实现

    2. **Tomcat接收请求**: Coyote监听8080端口,接收到HTTP请求后转发给Catalina。 3. **路由到Servlet**: Catalina解析请求,找到对应的Servlet实例。 4. **Servlet处理请求**: Servlet执行业务逻辑,可能涉及数据库...

    Java开发相关软件安装包 apache-tomcat-7.0.88

    - 解析HTTP请求:当用户通过浏览器访问Web应用时,Tomcat接收请求。 - 调用Servlet:根据请求的URL,Tomcat将请求转发到对应的Servlet进行处理。 - 渲染JSP页面:Servlet生成的动态内容可以通过JSP转换成HTML发送回...

    SpringBootWeb请求响应

    2. **Tomcat 接收请求**:内置的 Tomcat 服务器接收到请求并进行初步解析。 3. **DispatcherServlet 分发请求**:DispatcherServlet 根据请求路径找到合适的 Controller 方法。 4. **Controller 处理请求**:...

    一个小餐饮管理系统。structs+sql2000+tomcat5

    用户通过浏览器发起HTTP请求,Tomcat接收请求,处理后通过Struts框架将结果返回给用户。 从文件名称列表“mks”来看,这可能是项目源代码或者备份文件的名称。不过,具体的内容无法推测,因为没有给出详细信息。...

    Tomcat请求处理UML序列图

    2. **TcpWorkerThread**:TCP协议处理线程,负责监听客户端连接并接收请求数据。 3. **Http11Protocol**:HTTP/1.1协议处理器,实现HTTP协议的具体逻辑。 4. **CoyoteAdapter**:连接适配器,将接收到的HTTP请求转换...

    自己写的JSP留言板

    3. Tomcat接收请求,根据URL映射找到相应的Servlet。 4. Servlet处理请求,可能包括验证登录信息,与MySQL数据库交互,保存或查询留言数据。 5. Servlet完成处理后,可能更新JSP页面,例如显示留言列表或登录状态,...

    springboot 接收https请求

    在Spring Boot框架中,接收HTTPS(安全套接层超文本传输协议)请求是构建安全Web服务的重要步骤。HTTPS提供了一种加密通信的方式,确保数据在客户端和服务器之间传输时不会被中间人窃取或篡改。本文将详细介绍如何在...

    Java16道面试题及答案

    - Tomcat接收请求并映射到相应的Servlet。 - 如果Servlet尚未加载,Tomcat会加载并实例化Servlet。 - Tomcat调用Servlet的`init()`方法进行初始化。 - Servlet的`service()`方法处理请求。 - 使用监听器类跟踪...

    Java Web基础知识

    当客户端发起HTTP请求时,Tomcat接收请求并将其转发给相应的Servlet。Servlet处理请求后,将响应结果返回给客户端。这一过程涉及到了Servlet容器与Servlet之间的交互,以及请求与响应对象的传递。 **2.3 Tomcat目录...

    TOMCAT原理详解及请求过程

    2. **Connector**接收请求,并将其转换成内部请求对象。 3. **Connector**将请求对象传递给对应的`Engine`。 4. `Engine`根据请求中的虚拟主机名选择合适的`Host`。 5. `Host`再根据请求中的上下文路径选择对应的`...

    Java_EE中文乱码问题解决方案.ppt

    6. **调整Tomcat服务器配置**:修改Tomcat的`server.xml`文件,添加`URIEncoding="UTF-8"`属性到HTTP连接器配置中,以确保Tomcat接收请求时能正确处理UTF-8编码。 7. **数据库的编码设置**:大多数数据库系统支持...

    精通strust技术

    2. Tomcat接收请求并将其传递给Struts的ActionServlet。 3. ActionServlet解析请求,并根据`struts-config.xml`中的配置,找到对应的Action类。 4. 实例化ActionForm对象,用于接收和验证用户输入的数据。 5. 调用...

    图书管理信息系统

    总的来说,图书管理信息系统是一个典型的B/S(Browser/Server)架构应用,其工作流程大致为:用户通过浏览器发送请求到服务器,Tomcat接收请求并转发给Struts框架;Struts根据配置文件找到对应的Action类,执行Java...

    一个简单的上传下载网站

    在这个网站中,用户通过浏览器发送HTTP请求到服务器,服务器上的Tomcat接收请求,调用对应的Servlet进行处理,处理完成后,Servlet会将结果返回给客户端,用户可以在JSP页面上看到反馈信息。 【标签】:“网站 上传...

    面试相关资料、所点乱但对毕业生有帮助

    Tomcat接收请求后,根据URL找到对应的Servlet。 3. Tomcat调用Servlet的`service()`方法,进一步调用`doGet()`或`doPost()`等方法处理请求。 4. 处理完请求后,Servlet通过HTTP响应对象将结果返回给客户端。 - **...

Global site tag (gtag.js) - Google Analytics