Tomcat8.5.34请求过程简述

Tomcat(V8.5.34)请求响应过程简述

1,Tomcat介绍

  1. Tomcat扮演的角色?
      Tomcat作为web容器管理web应用程序生命周期,按照Servlet规范并发处理Http请求封装为对象,转发到业务场景的web程序处理,返回响应数据。tomcat作为最广泛应用web
    企业级容器之一。
  2. 为什么会存在?
      Tomcat实现了Servlet规范(对HTTP协议做面向对象封装),作为web容器存在。它封装Http多线程并发复杂的请求处理过程,简化Web应用开发难度,Web应用可以直接运行在该容器中,解耦业务处理场景。便于各自的维护。
    主要分析tomcat处理Http请求响应过程。

2,Tomcat主要处理请求响应的类

  Tomcat基于Socket来处理请求,响应。该Tomcat版本,protocol="HTTP/1.1"的默认处理类为org.apache.coyote.http11.Http11NioProtocol。该protocol是Nio同步非阻塞来处理网络请求。可以知道Connector的处理Socket三种方式:Nio,Nio2,Apr。通过修改protocol的org.apache.coyote.http11.Http11Nio2Protocol,org.apache.coyote.http11.Http11AprProtocol来设置。
本文针对Nio的请求方式。
Server.xml配置文件中:

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

Tomcat初始化过程Http11NioProtocol初始化时,会初始化NioEndpoint(处理Socket连接)。

public Http11NioProtocol() {
        super(new NioEndpoint());
    }

NioEndpoint.Acceptor侦听传入的TCP / IP连接(Socket套接字)并注册到Poller,Acceptor线程数由AbstracEndPoint的acceptorThreadCount成员变量控制,默认值为1。

protected class Acceptor extends AbstractEndpoint.Acceptor {

      @Override
      public void run() {

          int errorDelay = 0;

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

              // Loop if endpoint is paused
              while (paused && running) {
                  state = AcceptorState.PAUSED;
                  try {
                      Thread.sleep(50);
                  } catch (InterruptedException e) {
                      // Ignore
                  }
              }

              if (!running) {
                  break;
              }
              state = AcceptorState.RUNNING;

              try {
                  //if we have reached max connections, wait
                  countUpOrAwaitConnection();

                  SocketChannel socket = null;
                  try {
                      // Accept the next incoming connection from the server
                      // socket
                      socket = serverSock.accept();
                  } catch (IOException ioe) {
                      // We didn't get a socket
                      countDownConnection();
                      if (running) {
                          // 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 (running && !paused) {
                      // setSocketOptions() will hand the socket off to
                      // an appropriate processor if successful
                      //将已连接套接字交给Poller线程处理。
                      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;
      }
  	  .....
}
 protected int acceptorThreadCount = 1;

NioEndPoint.Poller主要用于以较少的资源轮询已连接套接字以保持连接,当数据可用时转给工作线程。poller线程数:

 /**
   * Poller thread count.
   */
  private int pollerThreadCount = Math.min(2,Runtime.getRuntime().availableProcessors());
//NioEndPoint内部类
public class Poller implements Runnable {
//省略代码
@Override
      public void run() {
          // Loop until destroy() is called
          while (true) {

              boolean hasEvents = false;

              try {
                  if (!close) {
                      hasEvents = events();
                      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;
              }
              //either we timed out or we woke up, process events first
              if ( keyCount == 0 ) hasEvents = (hasEvents | events());

              Iterator<SelectionKey> iterator =
                  keyCount > 0 ? selector.selectedKeys().iterator() : null;
              // Walk through the collection of ready keys and dispatch
              // any active event.
              while (iterator != null && iterator.hasNext()) {
                  SelectionKey sk = iterator.next();
                  NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
                  // Attachment may be null if another thread has called
                  // cancelledKey()
                  if (attachment == null) {
                      iterator.remove();
                  } else {
                      iterator.remove();
                      //处理有待处理事件的SelectionKey , 真正的处理都委托给了 worker 线程 
                      processKey(sk, attachment);
                  }
              }//while

              //process timeouts
              timeout(keyCount,hasEvents);
          }//while

          getStopLatch().countDown();
      }
protected void processKey(SelectionKey sk, NioSocketWrapper attachment) {
          try {
              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);
              }
          } catch ( CancelledKeyException ckx ) {
              cancelledKey(sk);
          } catch (Throwable t) {
              ExceptionUtils.handleThrowable(t);
              log.error("",t);
          }
      }
      //省略代码
}

processSocket方法调用EndNioPoint的父类org.apache.tomcat.util.net.AbstractEndpoint方法。

/**
     * Process the given SocketWrapper with the given status. Used to trigger
     * processing as if the Poller (for those endpoints that have one)
     * selected the socket.
     *
     * @param socketWrapper The socket wrapper to process
     * @param event         The socket event to be processed
     * @param dispatch      Should the processing be performed on a new
     *                          container thread
     *
     * @return if processing was triggered successfully
     */
    public boolean processSocket(SocketWrapperBase<S> socketWrapper,
            SocketEvent event, boolean dispatch) {
        try {
            if (socketWrapper == null) {
                return false;
            }
            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;
    }

上述主要为对Socket封装。

3,请求响应流程图

请求响应流程图
  内容不足之处,望大神留言指点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值