代码仓库cy/HowTomcatWork (gitee.com)
本节对应01-socket和02-HttpServer
socket
在 Java 里边,套接字指的是 java.net.Socket 类。要创建一个套接字,你可以使用 Socket 类众多构造方法中的一个。其中一个接收主机名称 host和端口号port
public Socket (java.lang.String host, int port)
在这里主机是指要连接的远程机器名称或者 IP 地址,端口是指远程应用的端口号。例如,要连接本机的 80 端口,new Socket (“127.0.0.1”, 80)
一旦你成功创建了一个 Socket 类的实例,你可以使用它来发送和接受字节流。
发送数据
要发送字节流,你首先必须调用Socket 类的 getOutputStream 方法来获取一个 java.io.OutputStream 对象。
要 发 送 文 本 到 一 个 远 程 应 用 , 你 经 常 要 从 返 回 的 OutputStream 对 象 中 构 造 一 个 java.io.PrintWriter 对象。通过PrintWriter发送纯文本更方便
接收数据
要从连接的另一端接受字节流,你可以调用 Socket 类的 getInputStream 方法用来返回一个 java.io.InputStream 对象。
下面代码写了一个客户端程序,他将会连接本机的8888端口应用程序,并发送“hello”
public class TCPClient {
public static void main(String[] args) throws IOException {
//可能会出现的异常java.net.ConnectException: Connection refused
Socket socket = new Socket("127.0.0.1",8888);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello".getBytes());
outputStream.close();
}
}
ServerSocket
Socket 类代表一个客户端套接字,即任何时候你想连接到一个远程服务器应用的时候你构 造的套接字.
服务器的套接字和客户端的不同,因为你的服务器必须随时待命,因为它不知道一个客户端应用什么时 候会尝试去连接它。为了让你的服务器应用能随时待命,你需要使用 java.net.ServerSocket 类
ServerSocket 和 Socket 不同,服务器套接字的角色是等待来自客户端的连接请求。一旦服 务器套接字获得一个连接请求,它创建一个 Socket 实例来与客户端进行通信。 要创建一个服务器套接字,你需要使用 ServerSocket 类提供的四个构造方法中的一个。你需要指定 IP 地址和服务器套接字将要进行监听的端口号。
通常,IP 地址将会是 127.0.0.1,也就是说,服务器套接字将会监听本地机器。服务器套接字正在监听的 IP 地址被称为是绑定地址。
服务器套接字的另一个重要的属性是 backlog,这是服务器套接字开始拒绝传入的请求之前,传 入的连接请求的最大队列长度。
其中一个 ServerSocket 类的构造方法如下所示
public ServerSocket(int port, int backLog, InetAddress bindingAddress);
对于这个构造方法,绑定地址必须是 java.net.InetAddress 的一个实例。
一种构造 InetAddress 对象的简单的方法是调用它的静态方法 getByName,传入一个包含主机名称的字符 串,例如 InetAddress.getByName(“127.0.0.1”);
下面一行代码构造了一个监听的本地机器 8080 端口的 ServerSocket,它的 backlog 为 1。
new ServerSocket(8080, 1, InetAddress.getByName(“127.0.0.1”));
这个ServerSocket 实例会监听本机的8080端口,等待客户端的连接请求。
获取客户端的连接请求通过调用 ServerSocket 类的 accept 方法。这个方法只 会在有连接请求时才会返回,并且返回值是一个 Socket 类的实例。没有连接会一直等待连接。
public class TCPServer {
public static void main(String[] args) throws IOException {
//服务器启动后会在这等待客户端的连接
ServerSocket server = new ServerSocket(8888);
//这个方法会阻塞,直到有客户端连接
Socket accept = server.accept();
InputStream inputStream = accept.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
System.out.println(new String(bytes,0,len));
inputStream.close();
}
}
HttpServer
接下来,我通过ServerSocket 包装一个类HttpServer
详细代码在我的仓库cy/HowTomcatWork (gitee.com)的02-HttpServer
public class HttpServer {
/** WEB_ROOT is the directory where our HTML and other files reside.
* System.getProperty("user.dir")得到项目的根路径
*/
public static final String WEB_ROOT =
System.getProperty("user.dir") + File.separator + "webroot";
// shutdown command
private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
// the shutdown command received
private boolean shutdown = false;
public static void main(String[] args) {
HttpServer server = new HttpServer();
server.await();
}
public void await() {
ServerSocket serverSocket = null;
int port = 8090;
try {
serverSocket = new ServerSocket(port, 10, InetAddress.getByName("127.0.0.1"));
}
catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
// Loop waiting for a request
while (!shutdown) {
Socket socket = null;
InputStream input = null;
OutputStream output = null;
try {
socket = serverSocket.accept();
input = socket.getInputStream(); //使用input得到客户端发送来的数据
output = socket.getOutputStream();//使用output向客户端发送数据
// create Request object and parse
Request request = new Request(input);
request.parse();
// create Response object
Response response = new Response(output);
response.setRequest(request);
response.sendStaticResource();
// Close the socket
socket.close();
//check if the previous URI is a shutdown command
shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
}
catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
}
web 服务器指定静态文件放置的目录:WEB_ROOT
public static final String WEB_ROOT = System.getProperty(“user.dir”) + File.separator + “webroot”;
代码列表包括一个叫 webroot 的目录,包含了一些你可以用来测试这个应用程序的静态资源。 为了请求一个静态资源,在你的浏览器的地址栏或者网址框里边敲入以下的 URL: http://machineName:port/staticResource
假如你正在使用同一台计算机上测试应用程序,并且想访问webroot目录下的index.html 文件,你可以使用一下的 URL: http://localhost:8080/index.html
代码会找到index.html, 并且读取文件中的数据并加上响应头组成Http响应包,如果文件找不到,我们发送的响应包如下,浏览器看到状态码404就知道页面找不到
要停止服务器,使用下面的 URL: http://localhost:8080/SHUTDOWN
仓库简介
我将代码端口改成8090,所以使用我仓库的代码运行后,在浏览器访问地址
http://localhost:8090/1.jpg
项目的大部分依赖放在lib文件夹里面,clone下来后需要手动添加为库。
模块how-tomcat-works-util放了org.apache.catelina包的源码,被后面的大多数模块使用,比如我在05-connector的pom文件中引入了模块how-tomcat-works-util