在上一篇文章里我们主要介绍了 tomcat NIO 的整体架构,以及在这个架构下的各个线程,在这里我们主要介绍 acceptor 线程。
在tomcat NIO 中会有一个独立的 acceptor 线程,主要负责接监听端口,接受连接请求,并将请求事件注册到 poller 线程中,主要包括如下:
初始化server socket绑定监听端口
该工作主要在以前文章中介绍的架构类 NioEndpoint 的 initServerSocket 方法中完成,相关源代码如下:
protected void initServerSocket() throws Exception {
if (!getUseInheritedChannel()) {
serverSock = ServerSocketChannel.open();
socketProperties.setProperties(serverSock.socket());
InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
serverSock.socket().bind(addr,getAcceptCount());
} else {
// Retrieve the channel provided by the OS
Channel ic = System.inheritedChannel();
if (ic instanceof ServerSocketChannel) {
serverSock = (ServerSocketChannel) ic;
}
if (serverSock == null) {
throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
}
}
serverSock.configureBlocking(true); //mimic APR behavior
}
private boolean useInheritedChannel = false;
public void setUseInheritedChannel(boolean useInheritedChannel) {
this.useInheritedChannel = useInheritedChannel;
}
public boolean getUseInheritedChannel() {
return useInheritedChannel;
}
启动acceptor线程
该工作的完成主要是在以前文章中介绍的架构类 AbstractEndpoint 的 startAcceptorThread 方法中进行,相关源代码如下:
protected void startAcceptorThread() {
acceptor = new Acceptor<>(this);
String threadName = getName() + "-Acceptor";
acceptor.setThreadName(threadName);
Thread t = new Thread(acceptor, threadName);
t.setPriority(getAcceptorThreadPriority());
t.setDaemon(getDaemon());
t.start();
}
接受连接请求
该工作主要在上面介绍的 Acceptor 类的 run 方法中完成,相关核心源代码如下:
try {
socket = endpoint.serverSocketAccept();
} catch (Exception ioe) {
endpoint.countDownConnection();
if (endpoint.isRunning()) {
errorDelay = handleExceptionWithDelay(errorDelay);
throw ioe;
} else {
break;
}
}
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);
}
将请求事件注册到poller线程
该工作主要在以前文章中介绍的 NioEndpoint 的 setSocketOptions 方法和 Poller类中的 register 方法中完成,相关源代码如下:
//NioEndpoint
protected boolean setSocketOptions(SocketChannel socket) {
try {
socket.configureBlocking(false);
Socket sock = socket.socket();
socketProperties.setProperties(sock);
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(socket, bufhandler, selectorPool, this);
} else {
channel = new NioChannel(socket, bufhandler);
}
} else {
channel.setIOChannel(socket);
channel.reset();
}
NioSocketWrapper socketWrapper = new NioSocketWrapper(channel, this);
channel.setSocketWrapper(socketWrapper);
socketWrapper.setReadTimeout(getConnectionTimeout());
socketWrapper.setWriteTimeout(getConnectionTimeout());
socketWrapper.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
socketWrapper.setSecure(isSSLEnabled());
poller.register(channel, socketWrapper);
return true;
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
try {
log.error(sm.getString("endpoint.socketOptionsError"), t);
} catch (Throwable tt) {
ExceptionUtils.handleThrowable(tt);
}
}
return false;
}
//Poller
public void register(final NioChannel socket, final NioSocketWrapper socketWrapper) {
socketWrapper.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
PollerEvent r = null;
if (eventCache != null) {
r = eventCache.pop();
}
if (r == null) {
r = new PollerEvent(socket, OP_REGISTER);
} else {
r.reset(socket, OP_REGISTER);
}
addEvent(r);
}
目前先写到这里,下一篇文章里我们继续介绍 tomcat NIO 中的 poller 线程。