EndPoint的组件就是属于连接器Connector里面的。它是一个通信的端点,就是负责对外实现TCP/IP协议。EndPoint是个接口,它的具体实现类就是AbstractEndpoint,而AbstractEndpoint具体的实现类就有AprEndpoint、Nio2Endpoint、NioEndpoint。

AprEndpoint:对应的是APR模式,简单理解就是从操作系统级别解决异步IO的问题,大幅度提高服务器的处理和响应性能。但是启用这种模式需要安装一些其他的依赖库。
Nio2Endpoint:利用代码来实现异步IO
NioEndpoint:利用了JAVA的NIO实现了非阻塞IO,Tomcat默认启动是以这个来启动的,而这个也是我们的讲述重点。

在代码NioEndpoint.class中定义的这五个组件。具体这五个组件是干嘛的呢?

LimitLatch:连接控制器,负责控制最大的连接数
Acceptor:负责接收新的连接,然后返回一个Channel对象给Poller
Poller:可以将其看成是NIO中Selector,负责监控Channel的状态
SocketProcessor:可以看成是一个被封装的任务类
Executor:Tomcat自己扩展的线程池,用来执行任务类

组件间的关联关系:

-----------------------------------------------------------

启动NioEndpoint的Acceptor多线程,默认初始化一个Acceptor:此处与8之前的版本有更新!!!

  1. package org.apache.tomcat.util.net
  1. public abstract class AbstractEndpoint<S>
  1. /**
    * Acceptor是接收连接的,我们可以看到Acceptor实现了Runnable接口,
    * 那么在哪会新开启线程来执行Acceptor的run方法呢?
    * 在AbstractEndpoint的startAcceptorThreads方法中。
    */
    protected final void startAcceptorThreads() {
    int count = getAcceptorThreadCount();
    acceptors = new Acceptor[count];
  2.  
  3. 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();
    }
    }
  1. @Override
    protected AbstractEndpoint.Acceptor createAcceptor() {
    return new Acceptor();
    }
  2.  
  3. 具体类的实现内容:
    1、执行run方法,启动socket服务;
    2、关闭socket服务。
  1. /**
    * The background thread that listens for incoming TCP/IP connections and
    * hands them off to an appropriate processor.
    * 重要方法
    */
    protected class Acceptor extends AbstractEndpoint.Acceptor {
  2.  
  3. @Override
    public void run() {
  4.  
  5. int errorDelay = 0;
  6.  
  7. // Loop until we receive a shutdown command
    while (running) {
  8.  
  9. // Loop if endpoint is paused
    while (paused && running) {
    state = AcceptorState.PAUSED;
    try {
    Thread.sleep(50);
    } catch (InterruptedException e) {
    // Ignore
    }
    }
  10.  
  11. if (!running) {
    break;
    }
    state = AcceptorState.RUNNING;
  12.  
  13. try {
    //if we have reached max connections, wait (默认是 private int maxConnections = 10000;)
  1. countUpOrAwaitConnection();
  2.  
  3. 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;
  4.  
  5. // Configure the socket
    if (running && !paused) {
    // setSocketOptions() will hand the socket off to
    // an appropriate processor if successful
    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;
    }
  6.  
  7. private void closeSocket(SocketChannel socket) {
    countDownConnection();
    try {
    socket.socket().close();
    } catch (IOException ioe) {
    if (log.isDebugEnabled()) {
    log.debug(sm.getString("endpoint.err.close"), ioe);
    }
    }
    try {
    socket.close();
    } catch (IOException ioe) {
    if (log.isDebugEnabled()) {
    log.debug(sm.getString("endpoint.err.close"), ioe);
    }
    }
    }
    }
  1. package sun.nio.ch;
  1. ServerSocketChannelImpl.class
  1. public SocketChannel accept() throws IOException {
    synchronized(this.lock) {
    if (!this.isOpen()) {
    throw new ClosedChannelException();
    } else if (!this.isBound()) {
    throw new NotYetBoundException();
    } else {
    SocketChannelImpl var2 = null;
    int var3 = 0;
    FileDescriptor var4 = new FileDescriptor();
    InetSocketAddress[] var5 = new InetSocketAddress[1];
  2.  
  3. InetSocketAddress var6;
    try {
    this.begin();
    if (!this.isOpen()) {
    var6 = null;
    return var6;
    }
  4.  
  5. this.thread = NativeThread.current();
  6.  
  7. do {
    var3 = this.accept(this.fd, var4, var5);
    } while(var3 == -3 && this.isOpen());
    } finally {
    this.thread = 0L;
    this.end(var3 > 0);
  8.  
  9. assert IOStatus.check(var3);
  10.  
  11. }
  12.  
  13. if (var3 < 1) {
    return null;
    } else {
    IOUtil.configureBlocking(var4, true);
    var6 = var5[0];
    var2 = new SocketChannelImpl(this.provider(), var4, var6);
    SecurityManager var7 = System.getSecurityManager();
    if (var7 != null) {
    try {
    var7.checkAccept(var6.getAddress().getHostAddress(), var6.getPort());
    } catch (SecurityException var13) {
    var2.close();
    throw var13;
    }
    }
  14.  
  15. return var2;
    }
    }
    }
    }
  1. private int accept(FileDescriptor var1, FileDescriptor var2, InetSocketAddress[] var3) throws IOException {
    return this.accept0(var1, var2, var3);
    }
  2.  
  3. private native int accept0(FileDescriptor var1, FileDescriptor var2, InetSocketAddress[] var3) throws IOException;
  1.  

tomcat NIOEndpoint中的Acceptor实现的更多相关文章

  1. Tomcat应用中post方式传参数长度限制

    Tomcat应用中post方式传参数长度限制 jsp页面上是没有限制的,但是在tomcat服务器上有限制,Tomcat 默认的post参数的最大大小为2M, 当超过时将会出错,可以配置maxPostS ...

  2. 30天轻松学习javaweb_Eclipse在修改了web.xml后将自动更新到tomcat服务器中

    context.xml中增加<WatchedResource>WEB-INF/web.xml</WatchedResource>,Eclipse在修改了web.xml后将自动更 ...

  3. 使用外部容器运行spring-boot项目:不使用spring-boot内置容器让spring-boot项目运行在外部tomcat容器中

    前言:本项目基于maven构建 spring-boot项目可以快速构建web应用,其内置的tomcat容器也十分方便我们的测试运行: spring-boot项目需要部署在外部容器中的时候,spring ...

  4. linux服务器上tomcat日志中的中文乱码

    转: 修改tomcat应用日志默认编码格式 前言 今天开发跟我说tomcat日志中的中文不能正常显示,根据以往的经验,我觉得可能跟服务器的编码有关,于是尝试各种方法,但还是没能解决问题. 后来我突然想 ...

  5. 修改Tomcat服务中的端口配置

    1.修改Tomcat服务中的端口配置: 分别修改安装目录下的conf子目录中的server.xml文件(注意:两个文件中对应的端口号要不一样),修改如下 : a. 修改Shutdown端口(默认为80 ...

  6. Tomcat 应用中并行流带来的类加载问题

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/f-X3n9cvDyU5f5NYH6mhxQ作者:肖铭轩.王道环 随着 Java8 的不断流行, ...

  7. SpringBoot 源码解析 (七)----- Spring Boot的核心能力 - 自定义Servlet、Filter、Listener是如何注册到Tomcat容器中的?(SpringBoot实现SpringMvc的原理)

    上一篇我们讲了SpringBoot中Tomcat的启动过程,本篇我们接着讲在SpringBoot中如何向Tomcat中添加Servlet.Filter.Listener 自定义Servlet.Filt ...

  8. Docker 02 - 向 Docker 的 Tomcat 镜像中部署 Web 应用

    目录 1 下载 Docker 镜像 2 部署Web项目 2.1 通过Dockerfile自定义项目镜像 2.2 启动自定义镜像, 生成一个容器 2.3 另一种启动方式: 交互式启动 3 (附) 向镜像 ...

  9. SpringBoot2.0.4部署在tomcat容器中

    1.  修改启动类继承自SpringBootServletInitializer. 2. 重写config方法: @Overrideprotected SpringApplicationBuilder ...

随机推荐

  1. ACM算法模板 · 一些常用的算法模板-模板合集(打比赛专用)

    ACM算法模板 · 一些常用的算法模板-模板合集(打比赛专用)

  2. javaWeb的HttpServletRequest和HttpServletResponse

    HttpServletRequest HttpServletRequest对象是封装了用户的请求信息,包括请求参数去,请求头等信息,service()f方法中的两个HttpServletRequest ...

  3. python算法与数据结构-冒泡排序算法(32)

    一.冒泡排序介绍 冒泡排序(英语:Bubble Sort)是一种简单的排序算法.它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.遍历数列的工作是重复地进行直到没有再需要 ...

  4. redis cluster集群的原理

    redis集群的概述: 在以前,如果前几年的时候,一般来说,redis如果要搞几个节点,每个节点存储一部分的数据,得借助一些中间件来实现,比如说有codis,或者twemproxy,都有.有一些red ...

  5. 大数据之路week07--day05 (Hive的搭建部署)

    在之前博客中我有记录安装JDK和Hadoop和Mysql的过程,如果还没有安装,请先进行安装配置好,对应的随笔我也提供了百度云下载连接. 安装JDK:   https://www.cnblogs.co ...

  6. MessageBox页面消息弹出框类

    MessageBox页面消息弹出框类: public class MessageBox { /// <summary> /// 自定义弹出窗口内容,不跳转 /// </summary ...

  7. TCP/IP协议标准

    OSI(7层):应用层(Application),表示层(Presentation),会话层(Session),传输层(Transport),网络层(Network),数据链路层(Data Link) ...

  8. H3CNE学习5 STP

    一.STP 1.概念 2.STP开机默认会运行 二.STP操作 1.原理 2.根桥选举,首先比前面的ID,谁小谁就是根桥,如果ID一样就比较mac,谁小谁就是根桥 可以手动修改优先级,图中可以将swA ...

  9. LINQPad 应用

    https://www.linqpad.net/ 使用 LINQPad 调试linq以及lambda表达式 http://www.studyofnet.com/news/1168.html linq ...

  10. 2017.10.6 国庆清北 D6T1 排序

    题目描述 小Z 有一个数字序列a1; a2; .... ; an,长度为n,小Z 只有一个操作:选 定p(1<p<n),然后把ap 从序列中拿出,然后再插⼊到序列中任意位置. 比如a 序列 ...