Tomcat源码分析【十一】请求处理过程分析之Acceptor

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

文章首发于:clawhub.club


这个类其实比较简单,继承自Runnable接口,实现了run方法。
方法中主要都是一些状态的变化,这里只看比较重要的两个地方:

    @Override
        public void run() {

            int errorDelay = 0;

            // Loop until we receive a shutdown command
            while (endpoint.isRunning()) {
    //略。。。

                try {
                    //略。。。

                    U socket = null;
                    try {
                        // Accept the next incoming connection from the server
                        // socket
                        //看这里看这里!!!!第一处
                        socket = endpoint.serverSocketAccept();
                    } catch (Exception ioe) {
                        // We didn't get a socket
                        endpoint.countDownConnection();
                        if (endpoint.isRunning()) {
                            // Introduce delay if necessary
                            errorDelay = handleExceptionWithDelay(errorDelay);
                            // re-throw
                            throw ioe;
                        } else {
                            break;
                        }
                    }
                    // Successful accept, reset the error delay
                    errorDelay = 0;

                    // Configure the socket
                    if (endpoint.isRunning() && !endpoint.isPaused()) {
                        // setSocketOptions() will hand the socket off to
                        // an appropriate processor if successful
                        //看这里看这里!!!!第二处
                        if (!endpoint.setSocketOptions(socket)) {
                            endpoint.closeSocket(socket);
                        }
                    } else {
                        endpoint.destroySocket(socket);
                    }
                } catch (Throwable t) {
                   //略。。。
                }
            }
            state = AcceptorState.ENDED;
        }

有些代码略过去了,这个方法也比较简单,循环获取SocketChannel,并将socket封装成NioChannel注册到poller。

endpoint.serverSocketAccept()

     @Override
        protected SocketChannel serverSocketAccept() throws Exception {
            //ServerSocketChannel
            return serverSock.accept();
        }

这就是ServerSocketChannel中的方法了,获取SocketChannel。

endpoint.setSocketOptions(socket)

    /**
         * Process the specified connection.
         *
         * @param socket The socket channel
         * @return <code>true</code> if the socket was correctly configured
         * and processing may continue, <code>false</code> if the socket needs to be
         * close immediately
         */
        @Override
        protected boolean setSocketOptions(SocketChannel socket) {
            // Process the connection
            try {
                //disable blocking, APR style, we are gonna be polling it
                socket.configureBlocking(false);
                Socket sock = socket.socket();
                socketProperties.setProperties(sock);

                NioChannel channel = nioChannels.pop();
                if (channel == null) {
                    SocketBufferHandler bufhandler = new SocketBufferHandler(
                            socketProperties.getAppReadBufSize(),
                            socketProperties.getAppWriteBufSize(),
                            socketProperties.getDirectBuffer());
                    if (isSSLEnabled()) {
                        channel = new SecureNioChannel(socket, bufhandler, selectorPool, this);
                    } else {
                        channel = new NioChannel(socket, bufhandler);
                    }
                } else {
                    channel.setIOChannel(socket);
                    channel.reset();
                }
                getPoller0().register(channel);
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                try {
                    log.error("", t);
                } catch (Throwable tt) {
                    ExceptionUtils.handleThrowable(tt);
                }
                // Tell to close the socket
                return false;
            }
            return true;
        }

这个方法首先获取Socket,在将Socket封装到NioChannel中,最后将NioChannel注册到Poller中。
分析获取Poller和注册。

getPoller0()

      /**
         * Return an available poller in true round robin fashion.
         *
         * @return The next poller in sequence
         */
        public Poller getPoller0() {
            int idx = Math.abs(pollerRotater.incrementAndGet()) % pollers.length;
            return pollers[idx];
        }
     /**
         * The socket pollers.
         */
        private Poller[] pollers = null;
        private AtomicInteger pollerRotater = new AtomicInteger(0);

获取一个Poller.

Poller的register方法

     /**
             * Registers a newly created socket with the poller.
             *
             * @param socket The newly created socket
             */
            public void register(final NioChannel socket) {
                socket.setPoller(this);
                NioSocketWrapper ka = new NioSocketWrapper(socket, NioEndpoint.this);
                socket.setSocketWrapper(ka);
                ka.setPoller(this);
                ka.setReadTimeout(getConnectionTimeout());
                ka.setWriteTimeout(getConnectionTimeout());
                ka.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
                ka.setSecure(isSSLEnabled());
                PollerEvent r = eventCache.pop();
                ka.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
                if (r == null) r = new PollerEvent(socket, ka, OP_REGISTER);
                else r.reset(socket, ka, OP_REGISTER);
                addEvent(r);
            }
    private void addEvent(PollerEvent event) {
                events.offer(event);
                if (wakeupCounter.incrementAndGet() == 0) selector.wakeup();
            }
    private final SynchronizedQueue<PollerEvent> events =
                    new SynchronizedQueue<>();

最终将NioChannel传递到了Poller的register方法中,封装成PollerEvent,存入队列。
下一篇分析Poller是怎么处理PollerEvent。


来源:https://www.jianshu.com/u/9632919f32c3

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Tomcat源码分析【十一】请求处理过程分析之Acceptor

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏