以下是个人学习过程中的一点记录
在进行实验完成一个简单的web服务器之前,我们要对HTTP协议报文有一个更深的了解,以下即为请求报文
在平常使用web服务器时,我们关心请求方法(一般是GET/POST),URL,以及如果是POST方法我们还关心请求包体中的数据,因此我们需要对报文进行分解处理。
下面可以简单分析一下我们具体要执行的步骤
创建ServerSocket对象,利用serverSocket对象中的accept()函数等待请求的到达,之后处理完成后重新进行等待。
创建Request对象,主要进行分词提取出我们需要的方法,URL,以及报文。
创建Response对象,主要根据request后得到的请求方法采取不同的处理方式并输出。
执行时,获取inputstream和outputstream,分别提供给Request和Response对象。
1. 首先是web服务器类
构造ServerSocket函数,将其绑定为本机的8080端口
然后进入while循环,accept()函数等待,没有时就进行阻塞
然后将输入流输出流分别交给请求和响应函数
执行完毕后,关闭ServerSocket,让其重新进入while循环
2. request类
首先创建4个变量,输入流,url,方法,数据包体
然后在构造函数中,根据 方法,url,版本之间的空格进行spilit,然后一次进行赋值
最后创建get方法即可获取值
3.response类
首先创建输出流和请求类变量,然后根据构造函数进行赋值
然后根据方法的不同,进行不同的处理
首先建立一个HashMap,存取参数
当方法为POST时,spilit拿出数据体,并存入公共域
然后模拟控制器,执行必要功能(此处为叠加计算值)
最后将结果加入一段html段中一起显示
注意要加入响应头,否则无法解析,会报错并且不会显示
当方法为GET时,根据参数的提交方式,对url进行解析,取出参数并存入公共域
4.测试用前端根据个人要求修改,适当修改后台的模拟处理即可运行。
以下贴上完整代码
public class WebServer {
/**
*@param args
*/
public static void main(String[] args) {
// TODOAuto-generated method stub
ServerSocketserverSocket = null;
try {
// 使用本机
serverSocket = newServerSocket(8080, 1, InetAddress.getByName("localhost"));
}catch (IOException e) {
e.printStackTrace();
}
while (true) {
try {
// 等待连接
Socketsocket = serverSocket.accept();
InputStreaminput = socket.getInputStream();
OutputStreamoutput = socket.getOutputStream();
// request解析出url
Requestrequest = new Request(input);
// response输出
Responseresponse = new Response(output, request);
response.response();
socket.close();
}catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
}
public class Request {
// GET格式,类似也存在POST
// GET /test.html HTTP/1.1
// Host:localhost:8080
// Connection: keep-alive
// Upgrade-Insecure-Requests: 1
// User-Agent:Mozilla/5.0 (Windows NT 10.0;WOW64) AppleWebKit/537.36 (KHTML,
// likeGecko)Chrome/74.0.3729.169Safari/537.36
// Accept:
// text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
// Accept-Encoding:gzip,deflate,br
// Accept-Language:zh-CN,zh;q=0.9,en;q=0.8
private InputStream input = null;
private String url = null;
private StringBuffer body = new StringBuffer(4096);
private String method = null;
public Request(InputStream input) {
this.input = input;
try {
// 下面分解url,首先读取内容到body中
byte[] buffer = new byte[4096];
int len = input.read(buffer);
for (int i = 0; i < len; i++)
body.append((char) buffer[i]);
// 拿到报文要获取url,根据注释中的格式进行分析
url = body.toString().split(" ")[1];
method = body.toString().split(" ")[0];
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String getUrl() {
return url;
}
public String getBody() {
return body.toString();
}
public String getMethod() {
return method;
}
}
public class Response {
private OutputStream output;
private Request request;
HashMapmemory = new HashMap();
public Response(OutputStream output, Request request) {
this.output = output;
this.request = request;
}
public void response() {
byte[] bytes = new byte[4096];
FileInputStreamfilestream = null;
try {
if (request.getMethod().equals("POST")) {
// 拿出数据体,以KV对存储
Stringbody = request.getBody();
String[]bodys = body.split("\r|\n");
String[]parms = bodys[bodys.length - 1].split("&|=");
for (int i = 1; i < parms.length - 1; i += 2) {
memory.put(parms[i - 1], parms[i]);
}
// 此处模拟控制器
int result = 0;
result+= Integer.parseInt(memory.get("t1")) + Integer.parseInt(memory.get("t2"))
+ Integer.parseInt(memory.get("t3")) + Integer.parseInt(memory.get("t4"))
+ Integer.parseInt(memory.get("t5")) + Integer.parseInt(memory.get("t6"))
+ Integer.parseInt(memory.get("t7")) + Integer.parseInt(memory.get("t8"))
+ Integer.parseInt(memory.get("t9")) + Integer.parseInt(memory.get("t10"))
+ Integer.parseInt(memory.get("t11")) + Integer.parseInt(memory.get("t12"))
+ Integer.parseInt(memory.get("t13")) + Integer.parseInt(memory.get("t14"))
+ Integer.parseInt(memory.get("t15"));
Stringbuf = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML
4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n"
+"<html>\r\n" + "<head>\r\n"
+"<meta
http-equiv=\"Content-Type\" content=\"text/html;
charset=UTF-8\">\r\n"
+"<title>Insert title
here</title>\r\n" + "</head>\r\n" + "<body>\r\n" + "\r\n" + " 你的测试得分为"
+result + "</body>" + "</html>";
StringresponseHead = "HTTP/1.1 200 ok\r\nContent-Type:
text/html\r\nContent-Length: " + buf.length()
+"\r\n\r\n";
output.write(responseHead.getBytes());
output.write(buf.getBytes());
}else {
String[]parms = request.getUrl().split("\\?")[1].split("&|=");
for (int i = 0; i < parms.length - 1; i += 2) {
memory.put(parms[i], parms[i + 1]);
}
// 模拟控制器
Filefile = new File("./src" + request.getUrl().split("\\?")[0]);
if (file.exists()) {
filestream = new FileInputStream(file);
// 加入头
StringresponseHead = "HTTP/1.1 200 ok\r\nContent-Type:
text/html\r\nContent-Length: "
+file.length() + "\r\n\r\n";
output.write(responseHead.getBytes());
output.write((memory.get("name") + "你好").getBytes());
int len = 0;
while ((len = filestream.read(bytes, 0, 4096)) != -1) {
output.write(bytes, 0, len);
}
}else {
StringerrorMessage = "HTTP/1.1 404 File Not Found\r\n" + "Content-Type: text/html\r\n"
+"Content-Length: 23\r\n" + "\r\n" + "<h1>File Not Found</h1>";
output.write(errorMessage.getBytes());
}
}
}catch (Exception e) {
}finally {
try {
if (filestream != null)
filestream.close();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}