`
liudeh_009
  • 浏览: 239536 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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

阅读更多

      这次主要解析采用apr方式处理请求.apr用C实现,通过JNI调用,主要提升对静态资源(如HTML、图片、CSS、JS等)的访问性能.在tomcat下配置apr步骤:

  1.下载本地库tcnative-1.dll,放在%jdk%\bin目录下(见附件).

  2.在server.xml里配置listener,这个配置server.xml默认是有的

     

  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />

 

  3.在server.xml里配置apr connector

  

     <Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol" 
               connectionTimeout="20000" 
               redirectPort="8443" />

 

    在tomcat启动的时候,会调用Connector类的Start()方法,根据以上配置,Connector的start()方法里会调用Http11AprProtocol类的start()方法,如下:

  

       try {
            protocolHandler.start();
        } catch (Exception e) {
            String errPrefix = "";
            if(this.service != null) {
                errPrefix += "service.getName(): \"" + this.service.getName() + "\"; ";
            }

            throw new LifecycleException
                (errPrefix + " " + sm.getString
                 ("coyoteConnector.protocolHandlerStartFailed", e));
        }

 

   

   Http11AprProtocol类的start()方法又会调用AprEndpoint类的start()方法,如下:

     try {
            endpoint.start();
        } catch (Exception ex) {
            log.error(sm.getString("http11protocol.endpoint.starterror"), ex);
            throw ex;
        }

    AprEndpoint类的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) {
                workers = new WorkerStack(maxThreads);
            }

            // Start poller threads
            pollers = new Poller[pollerThreadCount];
            for (int i = 0; i < pollerThreadCount; i++) {
                pollers[i] = new Poller(false);
                pollers[i].init();
                pollers[i].setName(getName() + "-Poller-" + i);
                pollers[i].setPriority(threadPriority);
                pollers[i].setDaemon(true);
                pollers[i].start();
            }

            // Start comet poller threads
            cometPollers = new Poller[pollerThreadCount];
            for (int i = 0; i < pollerThreadCount; i++) {
                cometPollers[i] = new Poller(true);
                cometPollers[i].init();
                cometPollers[i].setName(getName() + "-CometPoller-" + i);
                cometPollers[i].setPriority(threadPriority);
                cometPollers[i].setDaemon(true);
                cometPollers[i].start();
            }

            // Start sendfile threads
            if (useSendfile) {
                sendfiles = new Sendfile[sendfileThreadCount];
                for (int i = 0; i < sendfileThreadCount; i++) {
                    sendfiles[i] = new Sendfile();
                    sendfiles[i].init();
                    sendfiles[i].setName(getName() + "-Sendfile-" + i);
                    sendfiles[i].setPriority(threadPriority);
                    sendfiles[i].setDaemon(true);
                    sendfiles[i].start();
                }
            }

            // Start acceptor threads
            acceptors = new Acceptor[acceptorThreadCount];
            for (int i = 0; i < acceptorThreadCount; i++) {
                acceptors[i] = new Acceptor();
                acceptors[i].setName(getName() + "-Acceptor-" + i);
                acceptors[i].setPriority(threadPriority);
                acceptors[i].setDaemon(getDaemon());
                acceptors[i].start();
            }

        }
    }

        该方法主要初始化接受socket的线程和处理socket的线程池.Acceptor的run()方法如下:

   

public void run() {

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

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

                if (!running) {
                    break;
                }
                try {
                    // Accept the next incoming connection from the server socket
                    long socket = Socket.accept(serverSock);
                    /*
                     * In the case of a deferred accept unlockAccept needs to
                     * send data. This data will be rubbish, so destroy the
                     * socket and don't process it.
                     */
                    if (deferAccept && (paused || !running)) {
                        destroySocket(socket);
                        continue;
                    }
                    // Hand this socket off to an appropriate processor
                    if (!processSocketWithOptions(socket)) {//把socket交给woker线程进行转发
                        // Close socket and pool right away
                        destroySocket(socket);
                    }
                } catch (Throwable t) {
                    if (running) {
                        String msg = sm.getString("endpoint.accept.fail");
                        if (t instanceof Error) {
                            Error e = (Error) t;
                            if (e.getError() == 233) {
                                // Not an error on HP-UX so log as a warning
                                // so it can be filtered out on that platform
                                // See bug 50273
                                log.warn(msg, t);
                            } else {
                                log.error(msg, t);
                            }
                        } else {
                                log.error(msg, t);
                        }
                    }
                }

            }

        }

    }

 

   Socket.accept(serverSock)方法的Socket类是用JNI实现的不同于java的Socket类,所以 Socket.accept(serverSock)返回的参数是long类型的.processSocketWithOptions(socket)方法如下:

    

    protected boolean processSocketWithOptions(long socket) {
        try {
            if (executor == null) {
                getWorkerThread().assignWithOptions(socket);
            } else {
                executor.execute(new SocketWithOptionsProcessor(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;
    }

 

   再来看一下woker线程的run方法():

  

public void run() {

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

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

                if (!deferAccept && options) {
                    if (setSocketOptions(socket)) {
                        getPoller().add(socket);//将sokcet交给poller转发.poller最终会把socket交给worker处理不知道为什么这么做
                    } else {
                        // Close socket and pool
                        destroySocket(socket);
                        socket = 0;
                    }
                } else {

                    // Process the request from this socket
                    if ((status != null) && (handler.event(socket, status) == Handler.SocketState.CLOSED)) {
                        // Close socket and pool
                        destroySocket(socket);
                        socket = 0;
                    } else if ((status == null) && ((options && !setSocketOptions(socket))
                            || handler.process(socket) == Handler.SocketState.CLOSED)) {//Http11AprProtocol.Http11ConnectionHandler.process(socket)处理socket
                        // Close socket and pool
                        destroySocket(socket);
                        socket = 0;
                    }
                }

                // Finish up this request
                recycleWorkerThread(this);

            }

        }

 

可以看到,woker的run()方法做了两件事.1.把socket交给poller.2.直接调用处理 Http11AprProtocol.Http11ConnectionHandler.process(socket)处理socket

 handler.process(socket)方法如下:    

 public SocketState process(long socket) {
            Http11AprProcessor processor = recycledProcessors.poll();
            try {
                if (processor == null) {
                    processor = createProcessor();
                }

                if (processor instanceof ActionHook) {
                    ((ActionHook) processor).action(ActionCode.ACTION_START, null);
                }

                SocketState state = processor.process(socket);//真正的解析http请求的方法
                if (state == SocketState.LONG) {//如果是长连接再放回线程池处理
                    // Associate the connection with the processor. The next request 
                    // processed by this thread will use either a new or a recycled
                    // processor.
                    connections.put(socket, processor);
                    proto.endpoint.getCometPoller().add(socket);
                } else {
                    recycledProcessors.offer(processor);
                }
                return state;

            } catch (java.net.SocketException e) {
                // SocketExceptions are normal
                Http11AprProtocol.log.debug
                    (sm.getString
                     ("http11protocol.proto.socketexception.debug"), e);
            } catch (java.io.IOException e) {
                // IOExceptions are normal
                Http11AprProtocol.log.debug
                    (sm.getString
                     ("http11protocol.proto.ioexception.debug"), e);
            }
            // Future developers: if you discover any other
            // rare-but-nonfatal exceptions, catch them here, and log as
            // above.
            catch (Throwable e) {
                // any other exception or error is odd. Here we log it
                // with "ERROR" level, so it will show up even on
                // less-than-verbose logs.
                Http11AprProtocol.log.error
                    (sm.getString("http11protocol.proto.error"), e);
            }
            recycledProcessors.offer(processor);
            return SocketState.CLOSED;
        }

     processor.process(socket)调用的是Http11AprProcessor类的process(long socket) 方法,用http协议对http请求进行解析

0
0
分享到:
评论

相关推荐

    tomcat8get请求url格式问题

    解决方式进入tomcat的server配置中进行添加参数配置 &lt;Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" relaxedPathChars="[]{}|\\^" ...

    apache-tomcat-8.5.50-src.zip

    分析Tomcat请求过程 链接器(Connector)与容器(Container) 解耦 Connector设计 监听服务端口,读取来自客户端的请求 将请求数据按照指定协议进行解析 根据请求地址匹配正确的容器进行处理 将响应返回客户端 ...

    Tomcat面试专题及答案.pdf

    maxThreads=”150”//Tomcat 使用线程来处理接收的每个请求。这个值表示 Tomcat 可创建的最大的线程数。默认值 200。可以根据机器的时期性能和内存 大小调整,一般可以在 400-500。最大可以在 800 左右。 ...

    《深入剖析Tomcat(中文版+英文版)》.rar

    4.7 处理请求 4.7.1 解析连接 4.7.2 解析请求 4.7.3 解析请求头 4.8 简单的container应用程序 4.9 小结 第5章 servlet容器 5.1 container接口 5.2 管道任务 5.2.1 pipeline接口 5.2.2 valve接口 5.2.3 ...

    tomcat工作原理深入解析

    Service是这样一个集合:它由一个或者多个Connector组成,以及一个Engine,负责处理所有Connector所获得的客户请求

    how-tomcat-works

    3.3.3.3 解析请求头(request header) 14 3.3.3.4 解析cookie 15 3.3.3.5 获取参数 16 3.3.3.6 创建HttpResponse对象 16 3.3.3.7 静态资源处理器和servlet处理器 17 第4章 tomcat的默认连接器 18 4.1 简介 18 4.2 ...

    01-Tomcat架构解析1

    2、Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应 3、Engine获得请求localhost/test/i

    How Tomcat Works: A Guide to Developing Your Own Java Servlet Container

    3.3.3.3 解析请求头(request header) 14 3.3.3.4 解析cookie 15 3.3.3.5 获取参数 16 3.3.3.6 创建HttpResponse对象 16 3.3.3.7 静态资源处理器和servlet处理器 17 第4章 tomcat的默认连接器 18 4.1 简介 18 4.2 ...

    看透springMvc源代码分析与实践

    7.5.2 Connector自身类74 7.5.3 ProtocolHandler77 7.5.4 处理TCP/IP协议的Endpoint77 7.5.5 处理HTTP协议的Processor80 7.5.6 适配器Adapter81 第二篇 俯视Spring MVC 第8章 Spring MVC之初体验84 8.1 环境...

Global site tag (gtag.js) - Google Analytics