注:为了单纯的了解连接器运行过程,与别的组件相关部分代码被注释了,该篇文章只是简单的对重点代码进行解释,理论知识可以参考《how tomcat works》这本书,感觉还是不错的。
1.启动(这是自己写的一个简单启动代码)
private static void start() {
HttpConnector connector = new HttpConnector();
connector.start();
}
2.HttpConnecter类中的start()方法
public void start() {
// Validate and update our current state
// if (started)
// throw new
// LifecycleException(sm.getString("httpConnector.alreadyStarted"));
threadName = "HttpConnector[" + port + "]";
// lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
//启动当前线程
threadStart();
// Create the specified minimum number of processors
while (curProcessors < minProcessors) {
if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
break;
HttpProcessor processor = newProcessor();
//将当前线程创建处理器加入处理器池中
recycle(processor);
}
}
3.HttpConnecter类中threadStart()方法
private void threadStart() {
// log(sm.getString("httpConnector.starting"));
// 启动当前的connector的线程
thread = new Thread(this, threadName);
// 设置为守护线程
thread.setDaemon(true);
thread.start();
}
4.HttpConnector类的run()方法
public void run() {
// Loop until we receive a shutdown command
while (!stopped) {
// Accept the next incoming connection from the server socket
Socket socket = null;
try {
socket = serverSocket.accept();
// 设置链接超时(假设设置为10分钟)以后,如果客户端socket和服务端socket链接以后10中以后会自动断开
// tcp链接,默认是一支不设置超时就是一直链接的
if (connectionTimeout > 0)
socket.setSoTimeout(connectionTimeout);
// 决定是否使用nagle算法,也就是将小数据报先不发送,附加在下一个数据包后面发送过来
socket.setTcpNoDelay(tcpNoDelay);
} catch (AccessControlException ace) {
log("socket accept security exception", ace);
continue;
} catch (IOException e) {
try {
// If reopening fails, exit
synchronized (threadSync) {
if (started && !stopped)
log("accept error: ", e);
if (!stopped) {
serverSocket.close();
// if (debug >= 3)
// log("run: Reopening server socket");
// serverSocket = open();
}
}
} catch (IOException ioe) {
log("socket reopen, io problem: ", ioe);
break;
} catch (KeyStoreException kse) {
log("socket reopen, keystore problem: ", kse);
break;
} catch (NoSuchAlgorithmException nsae) {
log("socket reopen, keystore algorithm problem: ", nsae);
break;
} catch (CertificateException ce) {
log("socket reopen, certificate problem: ", ce);
break;
} catch (UnrecoverableKeyException uke) {
log("socket reopen, unrecoverable key: ", uke);
break;
} catch (KeyManagementException kme) {
log("socket reopen, key management problem: ", kme);
break;
}
continue;
}
// Hand this socket off to an appropriate processor
// 启动完一个proccessor线程以后,先让它们处于wait状态,因为此时并没有需要处理的请求。
HttpProcessor processor = createProcessor();
if (processor == null) {
try {
// log(sm.getString("httpConnector.noProcessor"));
socket.close();
} catch (IOException e) {
;
}
continue;
}
// 将tcp连接封装的socket对象分配给Processor处理
processor.assign(socket);
// The processor will recycle itself when it finishes
synchronized (threadSync) {
threadSync.notifyAll();
}
}
}
5.HttpConnector类的assign()方法
synchronized void assign(Socket socket) {
// Wait for the Processor to get the previous Socket,默认为false
while (available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// Store the newly available Socket and notify our thread
this.socket = socket;
//通知processor的线程现在可以启动了
available = true;
//通知自己的在等待的线程可以激活了,他们会自己去竞争资源
//因为是用当前processor的对象来进行wait的(),因此就是通知当前processor的线程运行,而不是所有
//在等待processor线程
notifyAll();
if ((debug >= 1) && (socket != null))
log(" An incoming request is being assigned");
}
接下来看看与处理器创建相关代码,因为一个连接器中有可以有多个处理器,因此查看各个处理器创建的过程是很有必要的,这里的多个处理器采用的是处理器池是实现的,跟dbcp数据库连接池的实现方式很相似,接下来看代码
6.httpConnector中createProcessor()方法
注,其中processors的声明是这样的:
private Stack<Object> processors = new Stack<Object>();
private HttpProcessor createProcessor() {
synchronized (processors) {
// 池中有处理器可用
if (processors.size() > 0) {
return ((HttpProcessor) processors.pop());
}
// 如果处理器池中没有可以用的处理器,则判断当前的处理器个数(此时池中是空的)是否大于设置最大处理器个数,
if ((maxProcessors > 0) && (curProcessors < maxProcessors)) {
// 没有则创建
return (newProcessor());
} else {
// 如果处理器最大个数被设置为-1,则要多少个处理器就创建多少个,不受限制
if (maxProcessors < 0) {
return (newProcessor());
} else {
return (null);
}
}
}
}
7.httpConnector中newProcessor()方法
private HttpProcessor newProcessor() {
// 当创建一个处理器,则当前处理器标记加1,给改处理器设置了个名字,线程也是这么做的
HttpProcessor processor = new HttpProcessor(this, curProcessors++);
if (processor instanceof Lifecycle) {
try {
// 在HttpProcessor类中的start方法里启动processor线程(没创建一个处理器就马上启动,但是启动万以后并没有让processor的run方法马上执行,而是出于wait状态)
((Lifecycle) processor).start();
} catch (Exception e) {
log("newProcessor", e);
return (null);
}
}
created.addElement(processor);
return (processor);
}
接下来我们看看HttpProcessor中相关代码
1.HttpProcessor中start()方法
// 基本上都是用在start方法中启动自己的线程的。
public void start() // throws LifecycleException
{
// if (started)
// throw new LifecycleException
// (sm.getString("httpProcessor.alreadyStarted"));
// lifecycle.fireLifecycleEvent(START_EVENT, null);
// started = true;
threadStart();
}
2.HttpProcessor中start()方法
private void threadStart() {
//log(sm.getString("httpProcessor.starting"));
thread = new Thread(this, threadName);
//设置为守护线程,因为tomcat是为web应用程序服务的,所以他的线程一般都是守护线程
//同时,在守护线程中创建的线程即使不setDaemon,也是守护线程
thread.setDaemon(true);
//开启processor中的run方法。
thread.start();
if (debug >= 1)
log(" Background thread has been started");
}
3.HttpProcessor中run()方法
public void run() {
// Process requests until we receive a shutdown signal
while (!stopped) {
//当前线程等待下一个socket来以后激活所有的等等的线程(就是处理器创建以后不马上执行完,而是出于wait状态等待socket来以后并被别的线程激活)
Socket socket = await();
if (socket == null)
continue;
// Process the request from this socket
try {
//该方法就是处理socket,用户解析http头,创建request和response对象(以后会单独详细讲)
process(socket);
} catch (Throwable t) {
log("process.invoke", t);
}
// Finish up this request
connector.recycle(this);
// Tell threadStop() we have shut ourselves down successfully
synchronized (threadSync) {
threadSync.notifyAll();
}
}
4.HttpProcessor中await()方法
private synchronized Socket await() {
// Wait for the Connector to provide a new Socket
while (!available) {
try {
//就是调用当前对象的wait()方法
wait();
} catch (InterruptedException e) {
}
}
}
5.HttpProcessor中process()方法
public void process(Socket socket)
{
//该方法是处理http头和内容的,接下来会详细讲
}
到此,tomcat中连接器的运行过程基本结束了,怎么处理socket会在之后详细讲