0. Acceptor
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.jni.Error;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.res.StringManager;
public class Acceptor<U> implements Runnable {
private static final StringManager sm = StringManager.getManager(Acceptor.class);
private static final int INITIAL_ERROR_DELAY = 50;
private static final int MAX_ERROR_DELAY = 1600;
private final AbstractEndpoint<?,U> endpoint;
private String threadName;
// Acceptor的状态
protected volatile AcceptorState state = AcceptorState.NEW;
public enum AcceptorState {
NEW, RUNNING, PAUSED, ENDED
}
public Acceptor(AbstractEndpoint<?,U> endpoint) {
this.endpoint = endpoint;
}
@Override
public void run() {
int errorDelay = 0;
// Loop until we receive a shutdown command
while (endpoint.isRunning()) {
// 自旋挂起
// Loop if endpoint is paused
while (endpoint.isPaused() && endpoint.isRunning()) {
state = AcceptorState.PAUSED;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// Ignore
}
}
if (!endpoint.isRunning()) {
break;
}
state = AcceptorState.RUNNING;
try {
// 这个栅栏在之前初始化的时候说到了
// 控制最大连接数的
// 栅栏使用tomcat封装(基于 AtomicLong)后的类型 LimitLatch
// org.apache.tomcat.util.net.AbstractEndpoint#countUpOrAwaitConnection
// org.apache.tomcat.util.threads.LimitLatch#countUpOrAwait
// java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireSharedInterruptibly
// AQS的acquireSharedInterruptibly会尝试直到获取后返回(可以被中断的)
// 从该方法命名可以看出,连接超出将等待
//if we have reached max connections, wait
endpoint.countUpOrAwaitConnection();
// Endpoint might have been paused while waiting for latch
// If that is the case, don't accept new connections
if (endpoint.isPaused()) {
continue;
}
U socket = null;
try {
// 接收1个socket连接
// 初始化的时候,我们设置了阻塞
// 内部就 serverSocketChannel.accept()
// Accept the next incoming connection from the server
// socket
socket = endpoint.serverSocketAccept();
} catch (Exception ioe) {
// We didn't get a socket
endpoint.countDownConnection();
if (endpoint.isRunning()) {
// Introduce delay if necessary
errorDelay = handleExceptionWithDelay(errorDelay);
// re-throw
throw ioe;
} else {
break;
}
}
// 到这里,表示serverSocket已经成功接收了连接
// Successful accept, reset the error delay
errorDelay = 0;
// Configure the socket
if (endpoint.isRunning() && !endpoint.isPaused()) {
// step into ...
// 根据方法命名,这里应该只是简单设置了socket连接状态,并无业务处理的调用
// acceptor也因而可以尽快的接收下一个连接的到来
// setSocketOptions() will hand the socket off to
// an appropriate processor if successful
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 Error) {
Error e = (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);
}
}
}
state = AcceptorState.ENDED;
}
}
1. LimitLatch
// org.apache.tomcat.util.threads.LimitLatch
public class LimitLatch {
private class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1L;
public Sync() {
}
@Override
protected int tryAcquireShared(int ignored) {
// private final AtomicLong count;
long newCount = count.incrementAndGet();
if (!released && newCount > limit) {
// Limit exceeded
count.decrementAndGet();
return -1;
} else {
return 1;
}
}
}
2. NioEndpoint#setSocketOptions
// org.apache.tomcat.util.net.NioEndpoint#setSocketOptions
@Override
protected boolean setSocketOptions(SocketChannel socket) {
// Process the connection
try {
// clientSocketChannel设置非阻塞调用
//disable blocking, APR style, we are gonna be polling it
socket.configureBlocking(false);
// 得到 clientSocket
Socket sock = socket.socket();
socketProperties.setProperties(sock);
// private SynchronizedStack<NioChannel> nioChannels;
// NioChannel是tomcat封装的类型,内部维护了1个SocketChannel
// 这个nioChannel也是提前初始化好的channel实例
// 弹出1个channel来使用
// 这里弹出的处理:stack[index--] = null;
NioChannel channel = nioChannels.pop();
if (channel == null) {
// 不存在则直接实例化1个channel
SocketBufferHandler bufhandler = new SocketBufferHandler(
// 这个 handler 还维护了读、写的能力
socketProperties.getAppReadBufSize(),
socketProperties.getAppWriteBufSize(),
socketProperties.getDirectBuffer());
if (isSSLEnabled()) {
channel = new SecureNioChannel(socket, bufhandler, selectorPool, this);
} else {
channel = new NioChannel(socket, bufhandler);
}
} else {
// 将clientSocketChannel放到NioChannel中被委托
channel.setIOChannel(socket);
channel.reset();
}
// 将channel注册到其中的1个poller上
// Math.abs(pollerRotater.incrementAndGet()) % pollers.length;
getPoller0().register(channel);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
try {
log.error("",t);
} catch (Throwable tt) {
ExceptionUtils.handleThrowable(tt);
}
// Tell to close the socket
return false;
}
return true;
}
- Acceptor 在不间断的循环中控制连接数量
- 并将可处理的Channel添加到Poller的事件队列中