Tomcat简介
Tomcat服务器是一个轻量级的Java代码实现的Web服务器。这篇文章会讲述如何用Java实现一个简单的Tomcat服务器。
1.简易原理
- Tomcat开始运行后,会在服务器上开一个端口(本文中用的是8888端口),在所开辟的端口上运行一个ServerScoket,执行accpet()方法等待浏览器访问。
- 浏览器访问端口,ServerSocket的accept()方法返回一个运行在服务器端的socket,通过socket的getInputStream()方法和getOutputStream方法,可获得浏览器和服务器之间发送的内容和浏览器的响应内容()。
- 这里我们主要获取浏览器的请求地址和参数,响应时根据浏览器所传的参数和地址,到服务器上去寻找对应的资源(目前只支持静态资源),将用户请求的资源转化为文件流,传输给前端(浏览器)。
- 浏览器收到服务器的响应后,向用户展示界面。
2.实现类
主要分为以下几个类:
(1) Server 用于加载并启动服务器
(2) ServerThread 当接收到新请求时,开辟一个新的线程处理它
(3) Request 用于获取请求的数据(主要是请求的地址和请求参数)
(4) Response 用于响应请求(根据请求所获参数和地址,访问服务器上的资源)
(5) GetParam 用于获取环境变量参数
3.具体实现
package TomcatServer.server;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
public class Server {
private ServerSocket server; //服务
private int port; //端口号
private static Properties prop; //用于读取配置文件
//配置参数读取位置
static {
prop = new Properties();
try {
prop.load(new FileInputStream(new File("src/TomcatServer/source/property.properties")));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* @auther: Ragty
* @describe: 初始化服务器
* @param: []
* @return: void
* @date: 2019/1/24
*/
public void init() {
try {
port = Integer.parseInt(prop.getProperty("port"));
server = new ServerSocket(port);
System.out.println("服务器启动"+ port + "端口");
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* @auther: Ragty
* @describe: 在当前线程内,创建一个Client服务
* @param: []
* @return: void
* @date: 2019/1/25
*/
public void recive() {
try {
System.out.println("收到新请求");
Socket client = server.accept(); //监听服务器,平时等待连接,有client则创建客户端实例(阻塞的)
ServerThread thread = new ServerThread(client); //处理客户端请求,并返回请求页面
thread.start();
thread.join();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Server() {}
/*
* @auther: Ragty
* @describe: 启动Tomcat服务器
* @param: [args]
* @return: void
* @date: 2019/1/25
*/
public static void main(String[] args) {
Server server2 = new Server();
server2.init();
while (true) { //一直等待用户访问定义端口,访问后,开辟新线程处理它
server2.recive();
}
}
}
package TomcatServer.Request;
import TomcatServer.Util.GetParam;
import com.hjy.util.GetParm;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
public class Request {
private Socket client; //客户端
private BufferedReader reader;
private String url; //请求资源
private String method; //请求方式
private String protocal; //请求协议
private Map<String,String> map; //参数列表
private GetParam getParam; //请求参数分割工具
public Request() {}
/*
* @auther: Ragty
* @describe: 接收并客户端(Client)发出的请求,获取请求的链接及参数
* @param: [client]
* @return:
* @date: 2019/1/25
*/
public Request(Socket client) {
this.client = client;
map = new HashMap<>();
getParam = new GetParam();
try {
reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
String firstLine = reader.readLine();
String[] spilt = firstLine.split(" ");
method = spilt[0];
url = spilt[1];
protocal = spilt[2];
System.out.println(url);
if (method.equalsIgnoreCase("get")) {
if(url.contains("?")) {
String[] split2 = url.split("[?]");
url = split2[0]; //重新定义url
String property = split2[1];
map = getParam.getParam(property); //分割参数
}
} else {
int length = 0;
while (reader.ready()) { //确保已经缓冲完毕
String line = reader.readLine();
if (line.contains("Content-Length")) {
String[] spilt2 = line.split(" ");
length = Integer.parseInt(spilt2[1]);
}
if (line.equals("")) { //Post方法无参数
break;
}
}
String info = null;
char[] ch = new char[length];
reader.read(ch , 0, length);
info = new String(ch, 0, length);
map = getParam.getParam(info);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public Socket getClient() { return client; }
public void setClient(Socket client) { this.client = client; }
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
public String getMethod() { return method; }
public void setMethod(String method) { this.method = method; }
public String getProtocal() { return protocal; }
public void setProtocal(String protocal) { this.protocal = protocal; }
}
package TomcatServer.Response;
import java.io.*;
import java.net.Socket;
public class Response {
private Socket client;
private PrintStream ps;
private String path = null;
public Response() {};
/*
* @auther: Ragty
* @describe: 获取服务端传输给客户端的输出流
* @param: [client]
* @return:
* @date: 2019/1/24
*/
public Response(Socket client) {
super();
this.client = client;
try {
ps = new PrintStream(client.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* @auther: Ragty
* @describe:根据当前路径将服务器上有的资源用流传给客户端
* @param: []
* @return: void
* @date: 2019/1/24
*/
public void forword() throws FileNotFoundException {
FileInputStream fis = null;
try {
fis = new FileInputStream(new File(path));
ps.println("HTTP/1.1 200 OK");
ps.println();
byte[] buf = new byte[1024];
int length = 0;
while ( (length = fis.read(buf)) != -1 ) {
ps.write(buf, 0, length);
ps.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {fis.close();}
if (ps != null) {ps.close();}
if (client != null) {client.close();}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* @auther: Ragty
* @describe: 分情况处理请求Url(1.为空,返回默认资源 2.存在,加载该资源 3.不存在,返回错误信息)
* @param: [url]
* @return: void
* @date: 2019/1/24
*/
public void forword(String url) {
if (url.equals("/")) {
path = "src/TomcatServer/source/2.jpg";
} else {
path = "src/TomcatServer/source" + url;
File file = new File(path);
if (!file.exists()) { path = "src/TomcatServer/source/error.html"; }
}
try {
forword();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
4.测试效果
浏览器输入 http://localhost:8888 ,效果如下
浏览器输入 http://localhost:8888/success.html ,效果如下