tomcat NIOEndpoint中的Acceptor实现

Easter79
• 阅读 419

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自己扩展的线程池,用来执行任务类

组件间的关联关系:

tomcat NIOEndpoint中的Acceptor实现

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

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

package org.apache.tomcat.util.net;

public abstract class AbstractEndpoint<S>

/** * Acceptor是接收连接的,我们可以看到Acceptor实现了Runnable接口, * 那么在哪会新开启线程来执行Acceptor的run方法呢? * 在AbstractEndpoint的startAcceptorThreads方法中。 */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();    }}

@Overrideprotected AbstractEndpoint.Acceptor createAcceptor() {    return new Acceptor();}具体类的实现内容:1、执行run方法,启动socket服务;2、关闭socket服务。

/** * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. * 重要方法 */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  (默认是 private int maxConnections = 10000;)

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

package sun.nio.ch;

ServerSocketChannelImpl.class

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];            InetSocketAddress var6;            try {                this.begin();                if (!this.isOpen()) {                    var6 = null;                    return var6;                }                this.thread = NativeThread.current();                do {                    var3 = this.accept(this.fd, var4, var5);                } while(var3 == -3 && this.isOpen());            } finally {                this.thread = 0L;                this.end(var3 > 0);                assert IOStatus.check(var3);            }            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;                    }                }                return var2;            }        }    }}

private int accept(FileDescriptor var1, FileDescriptor var2, InetSocketAddress[] var3) throws IOException {    return this.accept0(var1, var2, var3);}private native int accept0(FileDescriptor var1, FileDescriptor var2, InetSocketAddress[] var3) throws IOException;
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
2年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
Wesley13 Wesley13
2年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Nginx + lua +[memcached,redis]
精品案例1、Nginxluamemcached,redis实现网站灰度发布2、分库分表/基于Leaf组件实现的全球唯一ID(非UUID)3、Redis独立数据监控,实现订单超时操作/MQ死信操作SelectPollEpollReactor模型4、分布式任务调试Quartz应用
Stella981 Stella981
2年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
4个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k