Tomcat源码学习一 Tomcat实现基石Socket
简述
Tomcat是什么?相信做Java Web的都应该用过Tomcat,它是Web轻量级的应用服务器,或者说是一个Servlet容器。
通过浏览器(Http协议)请求我们的Servlet类配置的路径这个过程是怎样的?Tomcat通过传输层的Socket实现了一个ServerSocket类,等待浏览器的请求并将请求信息封装成Request实例,发送给相应的Servlet,并且将返回结果封装成Response返回给浏览器。
HttpServletRequest,HttpServletResponse 两个接口。相信大家都不会陌生,是Http协议的请求和响应。在servlet-api.jar包里这两个接口的实例是怎么来得。这就得在Tomcat源码中寻找答案了。
1.Socket简单实现
Socket又称套接字,是Tcp/Ip传输层的一种应用。下面模拟一个打电话场景.
/**
* 电话服务端
* step 1 创建serverSocket
* step 2 绑定地址和端口
* step 3 accept 等待客户端连接
*
*/
public class CallServer {
public static ServerSocket serverSocket;
public static Socket socket;
public static BufferedReader reader =null;
public static PrintWriter writer = null;
public CallServer(String host,int port) {
try {
serverSocket = new ServerSocket();
SocketAddress endpoint = new InetSocketAddress(InetAddress.getByName(host),port);
int backlog = 5;
serverSocket.bind(endpoint,5);
socket = serverSocket.accept();
System.out.println("Server---------李四 已经连接 接收李四消息!");
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg=null;
while((msg = reader.readLine())!=null){
System.out.println(msg);
}
writer = new PrintWriter(socket.getOutputStream());
writer.write("hello lisi");
writer.flush();
writer.close();
reader.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
CallServer zhangsan = new CallServer("127.0.0.1",8080);
}
}
/**
* 电话客户端
*/
public class CallClient {
private static Socket socket;
public static BufferedReader reader =null;
public static PrintWriter writer = null;
public CallClient(String host,int port) {
try {
socket = new Socket();
SocketAddress endpoint = new InetSocketAddress(InetAddress.getByName(host),port);
socket.connect(endpoint);
System.out.println("Client---------已经接通张三 接收张三消息!");
writer = new PrintWriter(socket.getOutputStream());
writer.write("hello zhangsan");
writer.flush();
socket.shutdownOutput();
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg=null;
while((msg = reader.readLine())!=null){
System.out.println(msg);
}
writer.close();
reader.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
CallClient lisi = new CallClient("127.0.0.1",8080);
}
}
注意:
1.在客户端或者服务端通过socket.shutdownOutput()都是单向关闭的,即关闭客户端的输出流并不会关闭服务端的输出流,所以是一种单方向的关闭流
2.通过socket.shutdownOutput()关闭输出流,但socket仍然是连接状态,连接并未关闭
3.如果直接关闭输入或者输出流,即:in.close()或者out.close(),会直接关闭socket
2.Tomcat Socket源码阅读
2.1 AbstractEndpoint.init()
抽象终端类 用来处理底层 socket 链接。它有三个实现类,分别是3中不同的连接方法。NioEndpoint,AprEndpoint,JIoEndpoint 首相看AbstractEndpoint初始化方法。
public final void init() throws Exception {
testServerCipherSuitesOrderSupport();
if (bindOnInit) {
bind();
bindState = BindState.BOUND_ON_INIT;
}
}
2.2 JIoEndpoint.bind()
public void bind() throws Exception {
if (acceptorThreadCount == 0) {
acceptorThreadCount = 1;
}
if (getMaxConnections() == 0) {
setMaxConnections(getMaxThreadsInternal());
}
if (serverSocketFactory == null) {
if (isSSLEnabled()) {
serverSocketFactory =
handler.getSslImplementation().getServerSocketFactory(this);
} else {
serverSocketFactory = new DefaultServerSocketFactory(this);
}
}
if (serverSocket == null) {
try {
if (getAddress() == null) {
serverSocket = serverSocketFactory.createSocket(getPort(),
getBacklog());
} else {
serverSocket = serverSocketFactory.createSocket(getPort(),
getBacklog(), getAddress());
}
} catch (BindException orig) {
String msg;
if (getAddress() == null)
msg = orig.getMessage() + " <null>:" + getPort();
else
msg = orig.getMessage() + " " +
getAddress().toString() + ":" + getPort();
BindException be = new BindException(msg);
be.initCause(orig);
throw be;
}
}
}
2.3 Acceptor 接收器类
protected class Acceptor extends AbstractEndpoint.Acceptor {
@Override
public void run() {
int errorDelay = 0;
while (running) {
while (paused && running) {
state = AcceptorState.PAUSED;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
}
if (!running) {
break;
}
state = AcceptorState.RUNNING;
try {
countUpOrAwaitConnection();
Socket socket = null;
try {
socket = serverSocketFactory.acceptSocket(serverSocket);
} catch (IOException ioe) {
countDownConnection();
errorDelay = handleExceptionWithDelay(errorDelay);
throw ioe;
}
errorDelay = 0;
if (running && !paused && setSocketOptions(socket)) {
if (!processSocket(socket)) {
countDownConnection();
closeSocket(socket);
}
} else {
countDownConnection();
closeSocket(socket);
}
} catch (IOException x) {
if (running) {
log.error(sm.getString("endpoint.accept.fail"), x);
}
} catch (NullPointerException npe) {
if (running) {
log.error(sm.getString("endpoint.accept.fail"), npe);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString("endpoint.accept.fail"), t);
}
}
state = AcceptorState.ENDED;
}
}
总结
Tomcat实现的基石是Socket,在这里只是简单的分析。也只是冰山一角。其中Socket编程还有很多知识,像Tcp/Ip协议,长连接,短连接等。