acceptor线程监听端口,接收客户端的连接请求,将客户端连接交给poller处理
acceptor线程主要处理了三件事情:
- 处理acceptor线程(自己这个线程)的暂停和停止
- 接收客户端连接
- 设置socket并提交到poller
Acceptor线程主要代码如下
public void run() {
int errorDelay = 0;
long pauseStart = 0;
try {
while (!stopCalled) {
// 1、处理暂停逻辑
while (endpoint.isPaused() && !stopCalled) {
if (state != AcceptorState.PAUSED) {
pauseStart = System.nanoTime();
// Entered pause state
state = AcceptorState.PAUSED;
}
if ((System.nanoTime() - pauseStart) > 1_000_000) {
// Paused for more than 1ms
try {
if ((System.nanoTime() - pauseStart) > 10_000_000) {
Thread.sleep(10);
} else {
Thread.sleep(1);
}
} catch (InterruptedException e) {
// Ignore
}
}
}
if (stopCalled) {
break;
}
state = AcceptorState.RUNNING;
try {
endpoint.countUpOrAwaitConnection();
if (endpoint.isPaused()) {
continue;
}
U socket = null;
try {
// 2、接收客户端连接
socket = endpoint.serverSocketAccept();
} catch (Exception ioe) {
endpoint.countDownConnection();
if (endpoint.isRunning()) {
errorDelay = handleExceptionWithDelay(errorDelay);
// re-throw
throw ioe;
} else {
break;
}
}
errorDelay = 0;
if (!stopCalled && !endpoint.isPaused()) {
// 3、如果正常接收到客户端连接,通过endpoint#setSocketOptions方法处理客户端连接。其实就是交给Poller线程
if (!endpoint.setSocketOptions(socket)) {
endpoint.closeSocket(socket);
}
} else {
endpoint.destroySocket(socket);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
String msg = sm.getString("endpoint.accept.fail");
// APR specific.
// Could push this down but not sure it is worth the trouble.
if (t instanceof org.apache.tomcat.jni.Error) {
org.apache.tomcat.jni.Error e = (org.apache.tomcat.jni.Error) t;
if (e.getError() == 233) {
// Not an error on HP-UX so log as a warning
// so it can be filtered out on that platform
// See bug 50273
log.warn(msg, t);
} else {
log.error(msg, t);
}
} else {
log.error(msg, t);
}
}
}
} finally {
stopLatch.countDown();
}
state = AcceptorState.ENDED;
}
Acceptor线程通过while询盘判断外部是否调用了停止,如果没有则不断循环。循环内部处理了三件事情
1、处理暂停和停止
外部调用了暂停之后,Acceptor线程进入sleep,外部线程调用resume恢复Acceptor或者调用stop停止Acceptor,都只是设置了状态,Acceptor怎么才能知道状态改变了呢?那么就需要sleep一段时间后恢复过来轮询状态位,Acceptor设置了三个级别的轮询
- 暂停1ms以内,直接忙等轮询
- 暂停1ms到10ms之间,每次sleep 1ms轮询一次
- 暂停10ms以上,每次sleep 10ms轮询1次
2、接收客户端连接
通过endpoint#serverSocketAccept方法接收客户端连接。NioEndpoint#serverSocketAccept直接调用serverSock#accept接收客户端连接
protected SocketChannel serverSocketAccept() throws Exception {
SocketChannel result = serverSock.accept();
// Bug does not affect Windows. Skip the check on that platform.
if (!JrePlatform.IS_WINDOWS) {
SocketAddress currentRemoteAddress = result.getRemoteAddress();
long currentNanoTime = System.nanoTime();
if (currentRemoteAddress.equals(previousAcceptedSocketRemoteAddress) &&
currentNanoTime - previousAcceptedSocketNanoTime < 1000) {
throw new IOException(sm.getString("endpoint.err.duplicateAccept"));
}
previousAcceptedSocketRemoteAddress = currentRemoteAddress;
previousAcceptedSocketNanoTime = currentNanoTime;
}
return result;
}
NioEndpoint启动时,把ServerSocket配置为阻塞模式(并没有利用Selector机制),所以NioEndpoint#serverSocketAccept方法会一直阻塞直到接收到客户端连接。由于Acceptor只会监听一个端口,所以阻塞在这里并没有什么问题
protected void initServerSocket() throws Exception {
if (getUseInheritedChannel()) {
Channel ic = System.inheritedChannel();
if (ic instanceof ServerSocketChannel) {
serverSock = (ServerSocketChannel) ic;
}
if (serverSock == null) {
throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
}
} else {
serverSock = ServerSocketChannel.open();
socketProperties.setProperties(serverSock.socket());
InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
serverSock.socket().bind(addr,getAcceptCount());
}
// 将serverSock设置成阻塞模式
serverSock.configureBlocking(true); //mimic APR behavior
}
3、设置socket并提交到poller
通过NioEndpoint#setSocketOptions来处理客户端连接,这里会将SocketChannel包装成NioSocketWrapper,提交给Poller
protected boolean setSocketOptions(SocketChannel socket) {
NioSocketWrapper socketWrapper = null;
try {
// NioChannel是可以复用的,如果缓存没有则创建一个
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, this);
} else {
channel = new NioChannel(bufhandler);
}
}
// 创建NioSocketWrapper
NioSocketWrapper newWrapper = new NioSocketWrapper(channel, this);
channel.reset(socket, newWrapper);
connections.put(socket, newWrapper);
socketWrapper = newWrapper;
// 设置socket属性,将SocketChannel配置为非阻塞模式
socket.configureBlocking(false);
socketProperties.setProperties(socket.socket());
socketWrapper.setReadTimeout(getConnectionTimeout());
socketWrapper.setWriteTimeout(getConnectionTimeout());
socketWrapper.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
// 最后提交给poller
poller.register(socketWrapper);
return true;
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
try {
log.error(sm.getString("endpoint.socketOptionsError"), t);
} catch (Throwable tt) {
ExceptionUtils.handleThrowable(tt);
}
if (socketWrapper == null) {
destroySocket(socket);
}
}
return false;
}