自己写一个http服务器
在了解tomcat之前,先自己尝试写一个http服务器
什么是http协议
HTTP 协议,全称超文本传输协议(Hypertext Transfer Protocol), 允许web服务器和浏览器通过Internet来发送和接受数据,是一种请求/响应协议。http底层使用TCP来进行通信。目前,http已经迭代到了2.x版本,从最初的0.9、1.0、1.1到现在的2.x,每个迭代都加了很多功能。
在http中,始终都是客户端发起一个请求,服务器接受到请求之后,然后处理逻辑,处理完成之后再发送响应数据,客户端收到响应数据,然后请求结束。在这个过程中,客户端和服务器都可以对建立的连接进行中断操作。
http版本区别
。。。
http请求
一个http协议的请求包含三部分:
- 请求的首行
- 方法 URI 协议/版本
- 请求的头部
- 主体内容
例子:
POST /rest HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Connection: close
cache-control: no-cache
Postman-Token: b0479ec3-4533-47bf-a354-dc22679f4110
User-Agent: PostmanRuntime/7.6.0
Accept: */*
Host: 127.0.0.1:8080
accept-encoding: gzip, deflate
content-length: 11
key1=value1
http响应
http响应包含三部分:
- 协议 状态 状态描述
- 响应的头部
- 主体内容
例子:
HTTP/1.1 200 ok
Content-Type: application/json
{"msg":"true","code":"0"}
客户端的编写
客户端可以用postman等工具或者自己编写实现,主要发送请求用。
服务端的编写
上面的总结知道了http协议的内容是什么了之后,直接就可以编程去解析协议的内容了,比如可以将请求内容序列化成一个自定义的Request类。
public class MyServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));
while (true) {
Socket socket = serverSocket.accept();
System.out.println("connect success! " + socket.getPort());
threadPool.execute(() -> {
try {
handle(socket);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
static ExecutorService threadPool = Executors.newFixedThreadPool(4, Executors.defaultThreadFactory());
public static void handle(Socket socket) throws IOException {
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
Request request = new Request(inputStream);//先处理inputStream
request.parse();
//reason: read ECONNRESET'
System.out.println(request.getHeaders());
PrintWriter out = new PrintWriter(outputStream, true);//convert chars to bytes stream
out.println("HTTP/1.1 200 ok");
out.println("Content-Type: application/json");
out.println();
JSONObject response = new JSONObject();
response.put("code", "0");
response.put("msg", "true");
out.println(response.toJSONString());
out.close();
socket.close();
}
static class Request {
private InputStream input;
private String uri;
private Map<String, String> parameters;
private Map<String, String> headers;
Request(InputStream input) {
this.input = input;
}
private void parse() throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(input));
boolean loop = true;
StringBuffer sb = new StringBuffer(8096);
while (loop) {
if (in.ready()) {
char[] buffer = new char[4096];
int i = 0;
int len = in.read(buffer, 0, buffer.length);
sb.append(buffer, 0, len);
if (len == -1 || len < 4096)
loop = false;
}
}
String requestString = sb.toString();
uri = parseUri(requestString);
headers = parseHeaders(requestString);
// System.out.println(requestString);
//todo 支持parameter解析
}
private String parseUri(String requestString) {
int index1, index2;
index1 = requestString.indexOf(' ');
if (index1 != -1) {
index2 = requestString.indexOf(' ', index1 + 1);
if (index2 > index1)
return requestString.substring(index1 + 1, index2);
}
return null;
}
private Map<String, String> parseHeaders(String requestString) {
HashMap<String, String> map = Maps.newHashMap();
int index1;
int index2;
index1 = requestString.indexOf("\r\n");
index2 = requestString.indexOf("\r\n", index1 + 2);
while (index2 - index1 > 1) {
String str = requestString.substring(index1 + 2, index2);
String[] strings = str.split(": ");
if (strings.length >= 2) {
map.put(strings[0], strings[1]);
}
index1 = index2;
index2 = requestString.indexOf("\r\n", index1 + 2);
}
return map;
}
public Map<String, String> getHeaders() {
return headers;
}
}
}