Tomcat源码笔记(六)Connector--Endpoint

58 篇文章 0 订阅
8 篇文章 1 订阅

目录

AbstractEndpoint

NioEndpoint

Acceptor

Poller

 SocketProcessor 

ConnectionHandler

Http11Processor


Endpoint端点,在Tomcat中也就是接收socket连接和处理连接的地方(ServerSocket.accept())

位于连接器组件Connector中的协议处理器ProtocolHandler中 

AbstractEndpoint声明了三个组件,Accepter,  SocketProcessor,以及一个Handler接口。

  • Accepter 顾名思义,ServerSocket.accept()接收socket连接
  • SocketProcessor  模板方法,子类实现具体的SocketProcessor类,处理接收到的socket,SocketProcessor处理完了就该转给具体协议层处理了
  • Handler  协议层创建的处理器,endpoint调用

暂时只看了一个子类NioEndpoint,NioEndpoint中还定义了一个组件Poller,由Accepter负责监听,接收到scoket连接后,Poller中使用Selector.select() 监听读写事件,若读写就绪,转给SocketProcessor处理。

AbstractEndpoint

抽象父类中除了下边设置连接属性的方法外

模板模式定义了bind()、startInternal 及 创建和启动Accepter、Processor,处理Socket的方法

bind() 绑定ServerSocket端口

startInternal() 创建和启动Accepter等组件

public abstract class AbstractEndpoint<S> {
    private volatile LimitLatch connectionLimitLatch = null;

    private Executor executor = null;
    protected Acceptor[] acceptors;

    // processor的缓存
    protected SynchronizedStack<SocketProcessorBase<S>> processorCache;

    protected abstract Acceptor createAcceptor();

    protected abstract SocketProcessorBase<S> createSocketProcessor(
            SocketWrapperBase<S> socketWrapper, SocketEvent event);

    public abstract void bind() throws Exception;
    public abstract void unbind() throws Exception;
    public abstract void startInternal() throws Exception;
    public abstract void stopInternal() throws Exception;

    public void init() throws Exception {
        if (bindOnInit) {
            bind();
            bindState = BindState.BOUND_ON_INIT;
        }
        //。。。
    }

    public final void start() throws Exception {
        if (bindState == BindState.UNBOUND) {
            bind();
            bindState = BindState.BOUND_ON_START;
        }
        startInternal();
    }

    protected final void startAcceptorThreads() {
        int count = getAcceptorThreadCount();
        acceptors = new Acceptor[count];

        for (int i = 0; i < count; i++) {
            acceptors[i] = createAcceptor();
            String threadName = getName() + "-Acceptor-" + i;
            acceptors[i].setThreadName(threadName);
            Thread t = new Thread(acceptors[i], threadName);
            t.setPriority(getAcceptorThreadPriority());
            t.setDaemon(getDaemon());
            t.start();
        }
    }

    public boolean processSocket(SocketWrapperBase<S> socketWrapper,
            SocketEvent event, boolean dispatch) {
        try {
            if (socketWrapper == null) {
                return false;
            }
             
            // 是否有可重用的 SocketProcessor 
            SocketProcessorBase<S> sc = processorCache.pop();
            if (sc == null) {
                sc = createSocketProcessor(socketWrapper, event);
            } else {
                sc.reset(socketWrapper, event);
            }
            Executor executor = getExecutor();
            if (dispatch && executor != null) {
                executor.execute(sc);
            } else {
                sc.run();
            }
        } catch (RejectedExecutionException ree) {
            getLog().warn(sm.getString("endpoint.executor.fail", socketWrapper) , ree);
            return false;
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            // This means we got an OOM or similar creating a thread, or that
            // the pool and its queue are full
            getLog().error(sm.getString("endpoint.process.fail"), t);
            return false;
        }
        return true;
    }
}

NioEndpoint

来看父类抽象方法bind() 和 startInternal()的实现

public class NioEndpoint extends AbstractJsseEndpoint<NioChannel> {

    private volatile ServerSocketChannel serverSock = null;

   @Override
    public void bind() throws Exception {
        // endpoint初始化的时候调用bind(), 创建serversocket
        serverSock = ServerSocketChannel.open();
        socketProperties.setProperties(serverSock.socket());
        // 获取端口号
        InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));

        // 绑定地址和定义连接队列最大多少 ,默认100
        serverSock.socket().bind(addr, getAcceptCount());
     
        serverSock.configureBlocking(true); //mimic APR behavior

        // 设置acceptor线程和poller数量
        if (acceptorThreadCount == 0) {
            acceptorThreadCount = 1;
        }
        if (pollerThreadCount <= 0) {
            pollerThreadCount = 1;
        }

        setStopLatch(new CountDownLatch(pollerThreadCount));

        // 如果启用了https连接,这里初始化jsse或者openssl相关类
        initialiseSsl();

        // 启动selector池
        selectorPool.open();
    }

   /**
     * Start the NIO endpoint, creating acceptor, poller threads.
     */
    @Override
    public void startInternal() throws Exception {

        if (!running) {
            running = true;
            paused = false;

            processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                    socketProperties.getProcessorCache());
            eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                            socketProperties.getEventCache());
            nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                    socketProperties.getBufferPool());

            // 创建执行器ThreadPoolExecutor (10, 200)
            if ( getExecutor() == null ) {
                createExecutor();
            }

            // 设置最大连接数,10000默认
            initializeConnectionLatch();

            // 启动Poller线程
            pollers = new Poller[getPollerThreadCount()];
            for (int i=0; i<pollers.length; i++) {
                pollers[i] = new Poller();
                Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
                pollerThread.setPriority(threadPriority);
                pollerThread.setDaemon(true);
                pollerThread.start();
            }

            // 启动acceptor
            startAcceptorThreads();
        }
    }

    @Override
    protected AbstractEndpoint.Acceptor createAcceptor() {
        return new Acceptor();
    }

    @Override
    protected SocketProcessorBase<NioChannel> createSocketProcessor(
            SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) {
        return new SocketProcessor(socketWrapper, event);
    }
}

Acceptor

serverSocket.accept() 监听接收连接,一旦有socket接入,更新连接数,封装socket并注册到Poller中

    protected class Acceptor extends AbstractEndpoint.Acceptor {

        @Override
        public void run() {
            int errorDelay = 0;

            // 死循环接收连接,直到接受到shutdown指令
            while (running) {

                // 当endpoint 被暂停,睡会
                while (paused && running) {
                    state = AcceptorState.PAUSED;
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }

                // shutdown指令
                if (!running) {
                    break;
                }

                state = AcceptorState.RUNNING;

                try {
                    // 增加连接数,当到达最大连接时会阻塞等待
                    countUpOrAwaitConnection();

                    SocketChannel socket = null;
                    try {
                        // socket accept()阻塞监听
                        socket = serverSock.accept();
                    } catch (IOException ioe) {
                        // 异常释放连接数
                        countDownConnection();
                        if (running) {
                            // 延迟报错,首次报错50ms,后续 * 2, 最大1600ms
                            // 为了防止特殊情况accept报错时,过度消耗cpu及触发日志记录
                            // 例如,到达最大打开文件数限制
                            errorDelay = handleExceptionWithDelay(errorDelay);
                            throw ioe;
                        } else {
                            break;
                        }
                    }
                    // Successful accept, reset the error delay
                    errorDelay = 0;

                    // Configure the socket
                    if (running && !paused) {
                        // 成功接收到一个socket, 进行封装和注册到poller
                        // 如果失败,关闭socket
                        if (!setSocketOptions(socket)) {
                            closeSocket(socket);
                        }
                    } else {
                        closeSocket(socket);
                    }
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    log.error(sm.getString("endpoint.accept.fail"), t);
                }
            }
            state = AcceptorState.ENDED;
        }

 org.apache.tomcat.util.net.NioEndpoint#setSocketOptions

   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);

            // nioChannels 是Niochannel 对象的缓存
            NioChannel channel = nioChannels.pop();
            if (channel == null) {
                // 缓存无可用,创建新的buffer 和 Niochannel
                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();
            }

            // poller数组中顺序取一个poller注册channel
            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;
    }

Poller

public class Poller implements Runnable {

    private Selector selector;

    private final SynchronizedQueue<PollerEvent> events =
                new SynchronizedQueue<>();

    private AtomicLong wakeupCounter = new AtomicLong(0);

    public Poller() throws IOException {
       this.selector = Selector.open();
    }
}

刚看到注册了,先来看注册NioChannel方法 

org.apache.tomcat.util.net.NioEndpoint.Poller#register

将Accepter接收到的NioChannel封装为一个注册事件PollerEvent,放入Poller组件的队列中,Poller线程在run方法中,消费事件进行注册,也就是将SocketChannel注册到Selector上(socketChannel.register(selector, .....))

       public void register(final NioChannel socket) {
            // 将NioChannel 绑定poller
            socket.setPoller(this);

            // NioChannel 封装类,设置属性
            NioSocketWrapper ka = new NioSocketWrapper(socket, NioEndpoint.this);
            socket.setSocketWrapper(ka);
            ka.setPoller(this);
            ka.setReadTimeout(getSocketProperties().getSoTimeout());
            ka.setWriteTimeout(getSocketProperties().getSoTimeout());
            ka.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
            ka.setSecure(isSSLEnabled());
            ka.setReadTimeout(getConnectionTimeout());
            ka.setWriteTimeout(getConnectionTimeout());

            // 设置对这个NioSocketWrapper关注读事件
            // 往事件队列中增加注册此NioSocket的事件,在poller.run中执行
            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) {
            // 添加队列并唤醒select
            events.offer(event);

            // 计数器,每次唤醒只调用一次wakeup
            if ( wakeupCounter.incrementAndGet() == 0 ) selector.wakeup();
        }

org.apache.tomcat.util.net.NioEndpoint.Poller#run

把socket注册到selector并关注读事件,阻塞select() 监听,监听到事件活动processKey()进行处理

      public void run() {
            // Loop until destroy() is called
            while (true) {

                boolean hasEvents = false;

                try {
                    if (!close) {
                        // 执行注册事件,执行成功返回true
                        hasEvents = events();
                        // 没有唤醒操作的化,阻塞select
                        if (wakeupCounter.getAndSet(-1) > 0) {
                            //if we are here, means we have other stuff to do
                            //do a non blocking select
                            keyCount = selector.selectNow();
                        } else {
                            keyCount = selector.select(selectorTimeout);
                        }
                        wakeupCounter.set(0);
                    }
                    if (close) {
                        events();
                        timeout(0, false);
                        try {
                            selector.close();
                        } catch (IOException ioe) {
                            log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);
                        }
                        break;
                    }
                } catch (Throwable x) {
                    ExceptionUtils.handleThrowable(x);
                    log.error("",x);
                    continue;
                }
                // select无结果或被中断、唤醒出来后,再处理一波事件
                if ( keyCount == 0 ) hasEvents = (hasEvents | events());

                Iterator<SelectionKey> iterator =
                    keyCount > 0 ? selector.selectedKeys().iterator() : null;

                // 循环就绪事件,处理对应的NioChannel
                while (iterator != null && iterator.hasNext()) {
                    SelectionKey sk = iterator.next();
                    NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
                   
                    if (attachment == null) {
                        iterator.remove();
                    } else {
                        iterator.remove();
                        processKey(sk, attachment);
                    }
                }//while

                // 处理超时socket,从selector移除它
                timeout(keyCount,hasEvents);
            }//while

            getStopLatch().countDown();
        }

        // PollerEvent 是一个Runnable
        // 执行PollerEvent队列事件,例如注册NioChannel,从selector移除,设置关注事件等
        // 代码上注册就是socket.register(selector, 注册)
        // 设置关注事件就是key.interestOps() | interestOps
        public boolean events() {
            boolean result = false;

            PollerEvent pe = null;
            for (int i = 0, size = events.size(); i < size && (pe = events.poll()) != null; i++ ) {
                result = true;
                try {
                    pe.run();
                    pe.reset();
                    if (running && !paused) {
                        eventCache.push(pe);
                    }
                } catch ( Throwable x ) {
                    log.error("",x);
                }
            }

            return result;
        }

org.apache.tomcat.util.net.NioEndpoint.Poller#processKey

移除当前SelectionKey就绪事件,处理读写事件

        protected void processKey(SelectionKey sk, NioSocketWrapper attachment) {
                if ( close ) {
                    cancelledKey(sk);
                } else if ( sk.isValid() && attachment != null ) {
                    if (sk.isReadable() || sk.isWritable() ) {
                        if ( attachment.getSendfileData() != null ) {
                            processSendfile(sk,attachment, false);
                        } else {
                            // 移除就绪事件
                            unreg(sk, attachment, sk.readyOps());
                            boolean closeSocket = false;
                            // Read goes before write
                            // 处理读写
                            if (sk.isReadable()) {
                                if (!processSocket(attachment, SocketEvent.OPEN_READ, true)) {
                                    closeSocket = true;
                                }
                            }
                            if (!closeSocket && sk.isWritable()) {
                                if (!processSocket(attachment, SocketEvent.OPEN_WRITE, true)) {
                                    closeSocket = true;
                                }
                            }
                            if (closeSocket) {
                                cancelledKey(sk);
                            }
                        }
                    }
                } else {
                    //invalid key
                    cancelledKey(sk);
                }
          
        }

org.apache.tomcat.util.net.AbstractEndpoint#processSocket

Poller将就绪的socket交给SocketProcessor来处理

    public boolean processSocket(SocketWrapperBase<S> socketWrapper,
            SocketEvent event, boolean dispatch) {

            // 缓存中查找是否有现成的processor
            SocketProcessorBase<S> sc = processorCache.pop();
            if (sc == null) {
                sc = createSocketProcessor(socketWrapper, event);
            } else {
                sc.reset(socketWrapper, event);
            }

            // 执行processor,处理socket事件
            Executor executor = getExecutor();
            if (dispatch && executor != null) {
                executor.execute(sc);
            } else {
                sc.run();
            }

        return true;
    }

 SocketProcessor 

处理poller中的就绪socket并将socket传递给对应的协议处理器的连接处理器解析socket内容

抽象AbstractEndpoint类中只定义了抽象方法创建SocketProcessor,不同的实现类中(AprEndpoint/NioEndpoint/Nio2Endpoint),即不同的IO模式有不同的SocketProcessor实现类

    protected abstract SocketProcessorBase<S> createSocketProcessor(
            SocketWrapperBase<S> socketWrapper, SocketEvent event);

主要处理代码如下一行,调用应用协议层Handler解析socket内容。还有其他的处理,例如SSL握手等,现不细看

getHandler().process(socketWrapper, event)

ConnectionHandler

ConnectionHandler定义在协议处理器ProtocolHandler接口的抽象类AbstractProtocol中,在new Http11NioProtocol()时候被创建并设置到endpoint中 

只关注普通的HTTP请求,所以只看核心的几行,创建Processor进行请求处理,Processor实现类和具体协议实现类相关,在具体协议的Processor实现类中真正解析socket内容。

Http11Processor

 HTTP11中的实现如下,关联当前Connector中的CoyoteAdapter对象

创建对象时, Http11Processor会绑定一对请求和响应对象,之后的解析简单来说就是为这两个对象设置各种属性

org.apache.coyote.http11.Http11Processor#service

此方法开始解析socket,根据Http协议解析socket内容将各种信息设置到Request和Response对象中,协议处理器ProtocolHandler的任务到这就完成了。

下一步需要交给Engine中部署的应用去实际处理,CoyoteAdapter作为Connector和Engine中间的连接组件对请求响应对象执行必要的处理,并交给Engine

 调用CoyoteAdapter处理请求响应对

 根据标志位来判断socket连接是否需要关闭和保持连接,是否需要继续Poll监听读,是否需要升级协议

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值