Tomcat

Tomcat之NioEndpoint源码分析

2020-05-08  本文已影响0人  love111

NioEndpoint涉及tomcat服务端是如何处理客户端的连接及数据处理的模型


NioEndpoint实现.png

NioEndpoint启动

endpoint#start方法启动调用链
org.apache.catalina.startup.Bootstrap#main
org.apache.catalina.startup.Bootstrap#start
org.apache.catalina.startup.Catalina#start
org.apache.catalina.util.LifecycleBase#start
org.apache.catalina.core.StandardServer#startInternal
org.apache.catalina.util.LifecycleBase#start
org.apache.catalina.core.StandardService#startInternal
org.apache.catalina.util.LifecycleBase#start
org.apache.catalina.connector.Connector#startInternal
org.apache.coyote.AbstractProtocol#start
org.apache.tomcat.util.net.AbstractEndpoint#start
开始启动NIO的endpoint


image.png

①、创建executor执行器线程池
corePoolSize核心大小是10,最大maximumPoolSize是200的ThreadPoolExecutor


createExecutor.png
对于线程池调优可以通过maxThreads、minSpareThreads进行设置
image.png
②、初始化最大连接数connectionLimitLatch=8192
创建acceptor、poller线程并启动
image.png
③、开启poller线程
④、开启acceptor线程
image.png

acceptor、poller线程的运行

Acceptor线程启动

while (endpoint.isRunning()) {}
一直循环直到接收到一个shutdown 命令(Loop until we receive a shutdown command)
1、获取客户端连接的socket对象


image.png

2、把socket对象设置到endpoint中


image.png
①、分配NioChannel对象
image.png
②、分配NioSocketWrapper对象
image.png

根据NioChannel创建newWrapper对象
重置NioChannel中的SocketChannel sc和socketWrapper 参数
把当前连接缓存到connections集合中
socketWrapper赋值为newWrapper对象
设置当前socket为非阻塞
③、为socketWrapper设置参数
socketWrapper就是对当前连接的socket的一个封装
3、把socketWrapper注册到Poller中
org.apache.tomcat.util.net.NioEndpoint.Poller#register


register.png
new PollerEvent(socket, OP_REGISTER)是对当前socket和注册感兴趣的事件
org.apache.tomcat.util.net.NioEndpoint.Poller#addEvent
addEvent.png
events是SynchronizedQueue<PollerEvent> 对象
添加到events中即是添加到SynchronizedQueue对象的Object[] queue数组中。
如果增长前wakeupCounter=-1会唤醒selector
所以,Acceptor线程启动就是接受客户端连接,并创建Socket通信并把封装后的对象添加到poller线程中的队列中
Poller线程的启动

创建Poller对象,会创建选择器selector =WindowsSelectorImpl


image.png

这个线程启动也是一个死循环
1、一直循环遍历events队列中是否有连接


run.png
events方法判断队列中是否有Acceptor线程添加的连接
events.png

2、有新连接便会调用processKey处理新连接


image.png
image.png
感兴趣的事件改为0
unreg.png
3、读准备就绪
设置当前通道事件是SocketEvent.OPEN_READ,准备读取数据(Data is available to be read.)
processSocket.png
4、processSocket处理Socket对象
org.apache.tomcat.util.net.AbstractEndpoint#processSocket
processSocket.png

创建SocketProcessorBase对象,这个对象也是一个实现了Runnable的线程。
sc任务放到线程池execute执行,调用到SocketProcessorBase的run方法


image.png
5、SocketProcessor socket处理器对象处理socket
org.apache.tomcat.util.net.NioEndpoint.SocketProcessor#doRun
doRun.png
首先获取NioChannel、SelectionKey、Poller对象
handshake = 0说明不需要握手,让handler(ConnectionHandler)处理这个socket。handler对象是处理连接的sockets的对象(Handling of accepted sockets.)。ConnectionHandler这个对象是连接处理的基本类,实现了AbstractEndpoint.Handler<S>
image.png
接下来便是交给处理器类processor = Http11Processor处理请求数据的Http协议

总结:

NioEndpoint的启动,启动了三个线程和一个执行器线程池。
Acceptor线程处理客户端的连接,并把连接封装添加到Poller线程中的events中。
Poller线程把连接socket添加到events中,在处理socket时,会启动一个处理连接的ConnectionHandler线程。
ConnectionHandler线程把处理的socket交给Http11Processor进行协议的处理。
ConnectionHandler线程是在线程池中执行。

上一篇 下一篇

猜你喜欢

热点阅读