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之前的版本有更新!!!

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();
}
}
@Override
protected 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;

最新文章

  1. Oracle:试图访问正在使用的事务临时表
  2. 在 ML2 中配置 Vlan Network- 每天5分钟玩转 OpenStack(93)
  3. linux centos6.5支持ipv6
  4. 《oracle每日一练》oracle截取字符的函数
  5. 在线PDF编辑网站http://www.pdfescape.com
  6. Linux crontab 定时任务
  7. leetcode 110 Balanced Binary Tree ----- java
  8. 定时器 corn 表达式
  9. 外部表查询时出现ORA-29913和ORA-29400错误
  10. SQL Server R2 2008中的SQL Server Management Studio 阻止保存要求重新创建表的更改问题的设置方法
  11. oc语言学习之基础知识点介绍(二):类和对象的进一步介绍
  12. iostat,mpstat,sar即时查看工具,sar累计查看工具
  13. ListView 实现多选/无线电
  14. Bootstrap登录样式
  15. @font-face 使用过程
  16. python 模块的概念介绍
  17. 【CSS3】动画
  18. Java多线程3:Thread中的实例方法
  19. BZOJ.5417.[NOI2018]你的名字(后缀自动机 线段树合并)
  20. sencha touch Model validations 自定义验证 二选一输入验证、重复验证、时间验证、比较验证、条件验证(2015-1-14)

热门文章

  1. virtual box 6.0 扩容原有磁盘空间 ubuntu18.04
  2. 安装k8s,高可用3 master安装脚本
  3. selenium常用的API(一)截屏
  4. 201671030116 宋菲菲 实验十四 团队项目评审&amp;课程学习总结
  5. Java - 框架之 MyBites
  6. python递归的最大层数?
  7. HttpMessageConverter(消息转换器 )和@responsebody使用(转)
  8. 2019/7/18 --1.&lt;%@ include file=&quot;&quot;%&gt;与&lt;jsp:include page=&quot;&quot;/&gt;两种方式的作用
  9. jsp+ ueditor word粘贴上传
  10. 【JS】闭包的理解