Tomcat8.5.34请求过程简述
Tomcat(V8.5.34)请求响应过程简述
1,Tomcat介绍
- Tomcat扮演的角色?
Tomcat作为web容器管理web应用程序生命周期,按照Servlet规范并发处理Http请求封装为对象,转发到业务场景的web程序处理,返回响应数据。tomcat作为最广泛应用web
企业级容器之一。 - 为什么会存在?
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,请求响应流程图
内容不足之处,望大神留言指点。