首先看BIO模式。
Server.conf配置连接器如下:
<Connector port="8081" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
protocol设定为"HTTP/1.1",这里指org.apache.coyote.http11.Http11Protocol,
相应的转换代码在Connector类里:
public void setProtocol(String protocol) {
if (AprLifecycleListener.isAprAvailable()) {
if ("HTTP/1.1".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.http11.Http11AprProtocol");
} else if ("AJP/1.3".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.ajp.AjpAprProtocol");
} else if (protocol != null) {
setProtocolHandlerClassName(protocol);
} else {
setProtocolHandlerClassName
("org.apache.coyote.http11.Http11AprProtocol");
}
} else {
if ("HTTP/1.1".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.http11.Http11Protocol");
} else if ("AJP/1.3".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.jk.server.JkCoyoteHandler");
} else if (protocol != null) {
setProtocolHandlerClassName(protocol);
}
}
}
我们这里没有apr 也没有ajp.所以ProtocolHandlerClassName就是org.apache.coyote.http11.Http11Protocol,Http11Protocol在init里,会初始化JioEndpoint。
以后的工作主要由JioEndpoint来处理请求连接,来看看JioEndpoint的init方法:
public void init()
throws Exception {
if (initialized)
return;
// Initialize thread count defaults for acceptor
if (acceptorThreadCount == 0) {
acceptorThreadCount = 1;
}
if (serverSocketFactory == null) {
serverSocketFactory = ServerSocketFactory.getDefault();
}
if (serverSocket == null) {
try {
if (address == null) {
serverSocket = serverSocketFactory.createSocket(port, backlog);
} else {
serverSocket = serverSocketFactory.createSocket(port, backlog, address);
}
} catch (BindException orig) {
String msg;
if (address == null)
msg = orig.getMessage() + " <null>:" + port;
else
msg = orig.getMessage() + " " +
address.toString() + ":" + port;
BindException be = new BindException(msg);
be.initCause(orig);
throw be;
}
}
//if( serverTimeout >= 0 )
// serverSocket.setSoTimeout( serverTimeout );
initialized = true;
}
主要目的就是创建ServerSocket,用于接收连接请求(废话,ServerSocket谁不知道)。
连接器启动时,会启动Http11Protocol,相应的启动JioEndpoint.
JioEndpoint 的start方法:
public void start()
throws Exception {
// Initialize socket if not done before
if (!initialized) {
init();
}
if (!running) {
running = true;
paused = false;
// Create worker collection
if (executor == null) {//目前executor都为空,非空的下一节会讨论
workers = new WorkerStack(maxThreads);//①.创建工作线程。
}
// Start acceptor threads
for (int i = 0; i < acceptorThreadCount; i++) {
Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i);
acceptorThread.setPriority(threadPriority);
acceptorThread.setDaemon(daemon);
acceptorThread.start(); //②.启动接收线程.
}
}
}
在①处,WorkerStack模拟一个栈,里面用数组存储工作线程(Tomcat这帮人就喜欢用数组),用来处理请求过来的socket.
在②处,启动一个接收线程,接收请求连接。
Acceptor代码如下:
/**
* Server socket acceptor thread.
*/
protected class Acceptor implements Runnable {
/**
* The background thread that listens for incoming TCP/IP connections and
* hands them off to an appropriate processor.
*/
public void run() {
// Loop until we receive a shutdown command
while (running) {
// Loop if endpoint is paused
while (paused) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// Ignore
}
}
// Accept the next incoming connection from the server socket
try {
Socket socket = serverSocketFactory.acceptSocket(serverSocket);
serverSocketFactory.initSocket(socket);
// Hand this socket off to an appropriate processor
if (!processSocket(socket)) {
// Close socket right away
try {
socket.close();
} catch (IOException e) {
// Ignore
}
}
}catch ( IOException x ) {
if ( running ) log.error(sm.getString("endpoint.accept.fail"), x);
} catch (Throwable t) {
log.error(sm.getString("endpoint.accept.fail"), t);
}
// The processor will recycle itself when it finishes
}
}
}
serverSocketFactory.acceptSocket用init方法里创建的severSocket accept一个连接Socket。然后processSocket(socket).
下面看processSocke(socket)方法:
protected boolean processSocket(Socket socket) {
try {
if (executor == null) { //目前executor都为空。
getWorkerThread().assign(socket);
} else {
executor.execute(new SocketProcessor(socket));
}
} catch (Throwable t) {
// This means we got an OOM or similar creating a thread, or that
// the pool and its queue are full
log.error(sm.getString("endpoint.process.fail"), t);
return false;
}
return true;
}
getWorkerThread()方法是从刚才创建的工作线程栈WorkerStack中取得一个工作线程。
这段代码很简单,就不说了,有兴趣看一下Tomcat的源代码(Class:JioEndpoint).
我们看一下工作线程类Worker吗。
protected class Worker implements Runnable {
protected Thread thread = null;
protected boolean available = false;
protected Socket socket = null;
/**
* Process an incoming TCP/IP connection on the specified socket. Any
* exception that occurs during processing must be logged and swallowed.
* <b>NOTE</b>: This method is called from our Connector's thread. We
* must assign it to our own thread so that multiple simultaneous
* requests can be handled.
*
* @param socket TCP socket to process
*/
synchronized void assign(Socket socket) {
// Wait for the Processor to get the previous Socket
while (available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// Store the newly available Socket and notify our thread
this.socket = socket;
available = true;
notifyAll();
}
/**
* Await a newly assigned Socket from our Connector, or <code>null</code>
* if we are supposed to shut down.
*/
private synchronized Socket await() {
// Wait for the Connector to provide a new Socket
while (!available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// Notify the Connector that we have received this Socket
Socket socket = this.socket;
available = false;
notifyAll();
return (socket);
}
/**
* The background thread that listens for incoming TCP/IP connections and
* hands them off to an appropriate processor.
*/
public void run() {
// Process requests until we receive a shutdown signal
while (running) {
// Wait for the next socket to be assigned
Socket socket = await();
if (socket == null)
continue;
// Process the request from this socket
if (!setSocketOptions(socket) || !handler.process(socket)) {
// Close socket
try {
socket.close();
} catch (IOException e) {
}
}
// Finish up this request
socket = null;
recycleWorkerThread(this);
}
}
/**
* Start the background processing thread.
*/
public void start() {
thread = new Thread(this);
thread.setName(getName() + "-" + (++curThreads));
thread.setDaemon(true);
thread.start();
}
}
首行看一下刚刚被调用的assign方法,Worker类通过available实现互斥。Available可理解为是否还有现成的Socket绑定在这个工作线程上,true表示有。Assign首先判断Available,如果有可用socket,即Available为true,说明前一个socket还没有开始处理,则wait直到被唤醒。 This method is called from our Connector's thread.告诉我们该方法由连接器线程调用。那么工作线程自己呢。看run方法,调用了await,按照上面的理解,如果没有可用的socket,即Available为false,则wait直到被唤醒。如果为true,刚马上拿走这个socket.并把Available设为false.就可以有新的Socket放进来了。
但这里有点问题,从WorkerStack栈出取出的Worker或者新建的Worker,Available肯定都为false.那么assign方法的while (available)循环就没有必要了。不清楚为什么作者这么写。
获得Socket之后交由handler去处理,这里的handler就
是Http11Protocol$Http11ConnectionHandler,处理流程,以会再讨论。
分享到:
相关推荐
《深入理解Tomcat 6.0 -- 9.0及源码分析》 Tomcat,作为Apache软件基金会的开源项目,是Java Servlet和JavaServer Pages(JSP)的开源Web应用服务器,也是世界上最受欢迎的轻量级应用服务器之一。本文将深入探讨...
通过阅读和分析源码,你可以了解Tomcat如何加载web应用程序,如何处理请求,以及如何管理线程池和连接器。同时,也可以深入研究JSP编译过程、会话管理、安全性和性能优化等方面。 对于Eclipse用户,利用其强大的...
【标题】"Tomcat6.0的源码包"提供了对Apache Tomcat 6.0这一版本的服务器软件的内部工作原理的深入了解。Tomcat是一款开源的Java Servlet容器,广泛用于部署Java Web应用程序。它是Java EE(现称为Jakarta EE)的一...
在Tomcat 6.0中,主要有两个连接器:BioC(基于Java BIO的连接器)和AprC(使用Apache Portable Runtime库的连接器)。源码分析可以帮助理解连接器如何接收和处理HTTP请求,并返回响应。 4. **JNDI服务** Tomcat内...
总结,Tomcat 6.0源码分析是一个深入了解Java Web服务器运行机制的过程,这不仅有助于我们理解Web服务器的工作原理,还能帮助我们优化应用性能、排查问题,甚至为开发自定义服务器提供基础。通过深入研究`apache-...
4. **连接器与协议处理**:Coyote是Tomcat处理HTTP请求的组件,它支持多种协议,如HTTP/1.1。源码中可以研究Coyote如何接收和解析HTTP请求,以及如何生成响应。 5. **JSP与Servlet**:Jasper组件负责将JSP文件转换...
标题 "Tomcat6.0" 暗示我们即将探讨的是Apache Tomcat 6.0版本,这是一个流行的开源Java Servlet容器,用于部署和运行Java Web应用程序。Tomcat是基于Java Servlet和JavaServer Pages (JSP) 技术的,它是Apache软件...
通过分析Tomcat 6.0的源码,开发者不仅可以学习到Servlet和JSP的运行机制,还可以了解到Web服务器的设计模式、性能优化以及安全性控制等方面的知识。这对于提升Java Web开发技能和理解服务器底层运作至关重要。
标题 "myeclipse+tomcat6.0+struts2开发的登录程序" 提供了我们正在探讨的技术栈,这是一个使用MyEclipse作为集成开发环境(IDE),Tomcat 6.0作为应用服务器,以及Struts2作为MVC框架来构建的登录应用程序。...
4. **连接器与协议处理**:Coyote作为Tomcat的连接器,负责监听端口,接收并解析HTTP请求。它支持多种协议处理器,如AJP(Apache JServ Protocol)和HTTP/1.1,这些处理器负责与客户端进行数据交换。 5. **线程池...
Tomcat6.0还提供了更好的可扩展性,通过模块化的设计,可以方便地添加或移除特定的功能模块,如连接器(Connector)和Valve(阀门)。Valve是Tomcat处理请求生命周期的关键组件,通过自定义Valve,开发者可以实现...
Tomcat由几个核心组件构成,包括Catalina(Servlet容器)、Jasper(JSP引擎)、 Coyote(HTTP连接器)和Commons组件。Catalina是Tomcat的核心,负责处理Servlet规范;Jasper解析并编译JSP页面为Servlet;Coyote处理...
4. **连接器(Connector)与引擎(Engine)**:Tomcat的核心架构包括Connector和Container,其中Connector负责接收和发送HTTP请求,Container负责处理请求。在`conf/server.xml`中,你可以配置这些组件。 5. **部署...
6. **源码分析**:压缩包中的源码可能包含以下部分:Struts的Action和ActionForm类,Spring的Service和DAO类,以及Hibernate的实体类和映射文件。这些源码提供了实际的业务处理和数据访问实现,通过阅读和理解这些...
1. **Tomcat架构**:Tomcat的核心架构分为几个主要组件,包括Catalina(核心Servlet容器)、Jasper(JSP编译器)、 Coyote(HTTP/HTTPS连接器)和Juli(日志系统)。每个组件都有其特定职责,协同工作以处理Web请求...
2. **源码分析**:对于技术爱好者,Roller的源码提供了一个了解Web应用程序开发和Java Servlet技术的好机会。通过阅读源码,可以学习到MVC(模型-视图-控制器)设计模式的实现,以及Spring框架、Hibernate持久层框架...
通过分析这个项目源码,学习者可以深入理解如何将JSTL标签与Servlet、JavaBean结合,构建动态Web应用程序。同时,项目在Tomcat 6.0上的成功运行,意味着它遵循了Java EE的规范,兼容旧版本的服务器,有助于学习者...