设为首页 收藏本站
查看: 361|回复: 0

[经验分享] Tomcat源码之AprEndpoint

[复制链接]

尚未签到

发表于 2017-1-25 10:40:31 | 显示全部楼层 |阅读模式
APR,全称Apache Portable Runtime,使用native server为Tomcat提供更好的伸缩性、更高的性能以及更强的集成能力。APR还是Apache HTTP Server2.x中的核心轻量级库,它可以提供更好的IO功能(如sendfile,epoll和OpenSSL)、OS功能和本地线程管理(共享内存、NT管道和UNIX套接字)。这些都可以使Tomcat变得更通用、更易扩展。
APR运行需要以下3个组件:APR Library、JNI Wapper for APR和OpenSSL Libary。如果以上功能已经安装,Tomcat在启动时会自动使用APR Connector。
与JIoEndPoint相比,AprEndpoint使用JNI的接口来获得对Socket的访问,功能实现要更为复杂,含有的线程更多:Acceptor Thread、Asynctimeout Thread、Poller Thread、Comet Poller Thread和Sendfile Thread。

Acceptor Thread、Asynctimeout Thread
功能与JIoEndpoint中的类似,同样是完成侦听和监控request的任务,不同的是这两个class直接继承Thread而不是实现Runnable接口。最终负责处理Socket的地方是在AjpConnectionHandler中,对应的处理线程(池)是Exector。
   
    protected class Acceptor extends Thread {
.....
    @Override
        public void run() {
            int errorDelay = 0;
            // Loop until we receive a shutdown command
            while (running) {
                ....
                try {
                    //if we have reached max connections, wait
                    awaitConnection();
                  
                    long socket = 0;
                    try {
                        // Accept the next incoming connection from the server
                        // socket
                        socket = Socket.accept(serverSock);
                    } catch (Exception e) {
                        // Introduce delay if necessary
                        errorDelay = handleExceptionWithDelay(errorDelay);
                        // re-throw
                        throw e;
                    }
                    // Successful accept, reset the error delay
                    errorDelay = 0;
                    //increment socket count
                    countUpConnection();
                    .....
                } catch (Throwable t) {
                    ....
                }
                }
                // The processor will recycle itself when it finishes
            }
        }
    }

   
    protected class AsyncTimeout implements Runnable {
      
        @Override
        public void run() {
            // Loop until we receive a shutdown command
            while (running) {
                ....
            long now = System.currentTimeMillis();
                Iterator<SocketWrapper<Long>> sockets =
                    waitingRequests.iterator();
                while (sockets.hasNext()) {
                    SocketWrapper<Long> socket = sockets.next();
                    if (socket.async) {
                        long access = socket.getLastAccess();
                        if ((now-access)>socket.getTimeout()) {
                            processSocketAsync(socket,SocketStatus.TIMEOUT);
                        }
                    }
                }
             ....                }
            }
        }
    }

Poller Thread
Poller类主要负责poll传入的socket连接(提供add(),由其他线程传入),如果发现有事件,交给AjpConnectionHandler处理。
    public class Poller extends Thread {
      ............
      
        public void add(long socket) {
            synchronized (this) {
                // Add socket to the list. Newly added sockets will wait
                // at most for pollTime before being polled
                if (addCount >= addS.length) {
                    // Can't do anything: close the socket right away
                    if (comet) {
                        processSocket(socket, SocketStatus.ERROR);
                    } else {
                        destroySocket(socket);
                    }
                    return;
                }
                addS[addCount] = socket;
                addCount++;
                this.notify();
            }
        }
      
        @Override
        public void run() {
         
                try {
                    // Add sockets which are waiting to the poller
                    if (addCount > 0) {
                        synchronized (this) {
                            int successCount = 0;
                            try {
                                for (int i = (addCount - 1); i >= 0; i--) {
                                    int rv = Poll.add(serverPollset, addS, Poll.APR_POLLIN);
                                    if (rv == Status.APR_SUCCESS) {
                                        successCount++;
                                    } else {
                                        // Can't do anything: close the socket right away
                                        if (comet) {
                                            processSocket(addS, SocketStatus.ERROR);
                                        } else {
                                            destroySocket(addS);
                                        }
                                    }
                                }
                            } finally {
                                keepAliveCount += successCount;
                                addCount = 0;
                            }
                        }
                    }
                    maintainTime += pollTime;
                    // Pool for the specified interval
                    int rv = Poll.poll(serverPollset, pollTime, desc, true);
                    if (rv > 0) {
                        keepAliveCount -= rv;
                        for (int n = 0; n < rv; n++) {
                            // Check for failed sockets and hand this socket off to a worker
                            if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP)
                                    || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)
                                    || (comet && (!processSocket(desc[n*2+1], SocketStatus.OPEN)))
                                    || (!comet && (!processSocket(desc[n*2+1])))) {
                                // Close socket and clear pool
                                if (comet) {
                                    processSocket(desc[n*2+1], SocketStatus.DISCONNECT);
                                } else {
                                    destroySocket(desc[n*2+1]);
                                }
                                continue;
                            }
                        }
                    }
              ..............
            } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    log.error(sm.getString("endpoint.poll.error"), t);
                }
            }
            synchronized (this) {
                this.notifyAll();
            }
        }
    }

Sendfile Thread
用于实现sendfile功能,它的工作流程跟Poller类似,add()中,将文件写入socket中。在run()中用Poll来轮询socket的状态,处理文件写入.
代码略....

初始化和启动
在bind()中完成对socket/SSL(如果要支持的话)等资源的初始化,在startInternal(),启动Poller线程组, Comet Poller线程组(两个都是Poller类),Sendfile线程组,Acceptor线程组和1个运行AsyncTimeout接口的线程组.

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-333217-1-1.html 上篇帖子: tomcat参数编码处理过程 下篇帖子: tomcat源码解析--Session
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表