目录
Tomcat在启动时,就已经将ServerSocket(或ServerSocketChannel等)初始化完毕,并启动了Acceptor线程等待请求到达。
请求预处理
在Acceptor线程的run方法中,有如下代码片段:
U socket = null;
try {
// Accept the next incoming connection from the server
// socket
socket = endpoint.serverSocketAccept();
} catch (Exception ioe) {
// 略
}
// Successful accept, reset the error delay
errorDelay = 0;
// Configure the socket
if (endpoint.isRunning() && !endpoint.isPaused()) {
// setSocketOptions() will hand the socket off to
// an appropriate processor if successful
if (!endpoint.setSocketOptions(socket)) {
endpoint.closeSocket(socket);
}
} else {
endpoint.destroySocket(socket);
}
关键语句就是 socket = endpoint.serverSocketAccept() 和 endpoint.setSocketOptions(socket)。
前者在NioEndpoint中,其实就是返回 serverSock.accept(),即获取一个请求。
后者则是对请求对象进行封装,在NioEndpoint中的实现如下:
protected boolean setSocketOptions(SocketChannel socket) {
NioSocketWrapper socketWrapper = null;
try {
// Allocate channel and wrapper
NioChannel channel = null;
if (nioChannels != null) {
channel = nioChannels.pop();
}
if (channel == null) {
SocketBufferHandler bufhandler = new SocketBufferHandler(
socketProperties.getAppReadBufSize(),
socketProperties.getAppWriteBufSize(),
socketProperties.getDirectBuffer());
if (isSSLEnabled()) {
channel = new SecureNioChannel(bufhandler, selectorPool, this);
} else {
channel = new NioChannel(bufhandler);
}
}
NioSocketWrapper newWrapper = new NioSocketWrapper(channel, this);
channel.reset(socket, newWrapper);
connections.put(socket, newWrapper);
socketWrapper = newWrapper;
// Set socket properties
// Disable blocking, polling will be used
socket.configureBlocking(false);
socketProperties.setProperties(socket.socket());
socketWrapper.setReadTimeout(getConnectionTimeout());
socketWrapper.setWriteTimeout(getConnectionTimeout());
socketWrapper.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
socketWrapper.setSecure(isSSLEnabled());
poller.register(channel, socketWrapper);
return true;
} catch (Throwable t) {
// 略
}
// Tell to close the socket if needed
return false;
}
可见是将请求封装成一个SocketWrapper。值得注意的是,在Tomcat的启动阶段,ServerSocketChannel被设置为同步(configureBlocking(true)),在这里又设置为false了,注释也做了解释,是为了应用Poller来多线程处理请求。
封装后,将SocketWrapper发送给Poller处理。register方法将N