手写web服务器
总结:
1.所有的java的web服务器底层对象都是ServerSocket对象.
2.请求的对象都是流化对象.socket对象中解析出inputstream和outputstream,in转化成request对象,out转化成response对象.
3.线程池的代码的编写.
1.webServer类
步骤:
1.定义端口号,serverSocket,线程池等属性.
2.创建对象时调用init()方法,init()方法调用时,创建线程池.
3.start()方法,死循环接收socket,并且提交任务到线程池中.
4.service()方法,从socket中解析出inputstream和outputstream,并定义request对象和response对象.
将in和out转换成对应的request对象和response对象.
5.交给serviceDispatcher 对象分发,具体处理request对象和response对象.
**
* 手写web服务器
*/
public class WebServer {
/*
定义服务器端口
*/
private int port = 8888;
/*
web服务器
*/
private ServerSocket serverSocket;
/*
线程池
*/
private ThreadPoolExecutor threadPoolExecutor;
/*
构造方法
*/
public WebServer() {
init();
}
/*
初始化web服务器
*/
public void init(){
try {
serverSocket = new ServerSocket(this.port);
threadPoolExecutor = new ThreadPoolExecutor(5,
10,
3, TimeUnit.SECONDS,
new ArrayBlockingQueue(20),
new ThreadPoolExecutor.DiscardPolicy()
);
System.out.println("服务器已经启动!!!");
}catch (Exception e){
e.printStackTrace();
}
}
/*
启动web服务器,并且接收收到的socket,并且交由线程池处理
*/
public void start() throws IOException {
while (true){
final Socket accept = serverSocket.accept();
threadPoolExecutor.submit(new Thread(){
@Override
public void run() {
service(accept);
}
});
}
}
/*
具体的业务
*/
public void service(Socket socket){
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
System.out.println("接收到客户端的消息,客户端:" +socket.getInetAddress() +
",端口号:" + socket.getPort());
Request request = new RequestParser().parse(inputStream);
Response response = new Response(outputStream);
service(request,response);
}catch (Exception e){
e.printStackTrace();
}finally {
if(socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 交由dispatcher对象处理具体的request和response对象
* @param request
* @param response
*/
private void service(Request request, Response response) {
ServiceDispatcher serviceDispatcher = new ServiceDispatcher();
serviceDispatcher.dispatcher(request,response);
}
}
2.request对象
步骤:
1.request对象中包含了请求的全部东西,这里可以定义很多属性,比如url.请求方式,请求参数,等等.
2.将属性从inputstream中解析出来,分别赋值到各个属性中.
/**
* 请求request
*/
public class Request {
/*
请求类型
*/
private String type;
/*
请求的url
*/
private String url;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
3.response对象
1.重构响应报文.
2.定义write方法,书写响应报文信息.
/**
* 响应对象
*/
public class Response {
private OutputStream output;
public Response(OutputStream output) {
this.output = output;
}
/**
* 输出文本信息
* @param text
* @throws IOException
*/
public void writeText(String text) {
FileInputStream fis = null;
try {
output.write("HTTP/1.1 200 OK\n".getBytes());
output.write("Content-Type: text/html; charset=UTF-8\n\n".getBytes());
output.write(text.getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
4.ServiceDispacher对象(请求转发对象)
步骤:
1.书写转发的方法,将接收到的参数request对象和response对象转发到具体的每一个servlet对象.
/**
* 类似于springmvc中的dispatcherServlet
*/
public class ServiceDispatcher {
public void dispatcher(Request request,Response response){
executeController(request, response);
}
/**
* 执行请求,并返回结果,这里主要是凭借相应头的方法
* @param request
* @param response
*/
private void executeController(Request request, Response response) {
String text = getControllerResult(request, response);
StringBuilder sb = new StringBuilder();
sb.append("请求类型: " + request.getType());
sb.append("<br/>请求URI: " + request.getUrl());
sb.append("<br/>返回结果: " + text);
// 输出控制器返回结果
System.out.println("响应:" + sb.toString());
response.writeText(sb.toString());
}
/**
* 模拟查找和执行控制器方法并返回结果,类似于将得到的request对象根据request的请求路径
* 去controller层找相关的映射路径
* @param request
* @param response
* @return
*/
private String getControllerResult(Request request, Response response) {
String text = "";
String uri = request.getUrl();
String [] uriArray = uri.split("\\/");
if(uriArray.length != 3) {
text = "请求路径没有找到相关匹配服务. ";
} else if("test".equalsIgnoreCase(uriArray[1])) {
TestController testController = new TestController();
if("test1".equalsIgnoreCase(uriArray[2])) {
text = testController.test1();
} else if("test2".equalsIgnoreCase(uriArray[2])) {
text = testController.test2();
} else {
text = "请求路径没有找到相关匹配服务. ";
}
} else {
text = "请求路径没有找到相关匹配服务. ";
}
return text;
}
}
5.requestParse解析器对象
步骤:
1.是将inputstream解析成request对象
2.读取inputstream中的信息.
3.解析请求方式.
/*
请求解析工具类,将inputStream解析成request对象
*/
public class RequestParser {
private final static int BUFFER_SIZE = 1024;
/*
经inputStream解析程request请求
*/
public Request parse(InputStream inputStream){
Request request = new Request();
//读取输入流中的信息
String message = readMessage(inputStream);
System.out.println("请求:" + message);
//读取输入流中的type
String type = parseType(message);
request.setType(type);
//读取输入流中的url
String url = parseUri(message);
request.setUrl(url);
return request;
}
/*
读取输入流中的信息
*/
private String readMessage(InputStream inputStream) {
//这是获取input中的信息
StringBuffer readMessage = new StringBuffer();
//这是每次读取的长度
int readLength = 0;
//
byte[] buffer = new byte[BUFFER_SIZE];
try {
//读取的长度
readLength = inputStream.read(buffer);
} catch (IOException e) {
e.printStackTrace();
readLength = -1;
}
//读取完成之后,将读取的东西,添加到字符串缓冲区中
for(int i = 0; i < readLength; i++) {
readMessage.append((char) buffer[i]);
}
//返回字符串
return readMessage.toString();
}
/**
* 解析请求方式
* @param requestString
* @return
*/
private String parseType(String requestString) {
int index = 0;
//从第一个空格开始截取
index = requestString.indexOf(' ');
if (index != -1) {
return requestString.substring(0, index);
}
return null;
}
/**
* 解析请求类型
* @param requestString
* @return
*/
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;
}
}
**6.TestController对象,映射测试对象**
public class TestController {
public String test1() {
return "TestController.test1() 调用成功";
}
public String test2() {
return "TestController.test2() 调用成功";
}
}
7.TestMain主测试对象
public class TestMain {
public static void main(String[] args) {
try {
new WebServer().start();
} catch (IOException e) {
e.printStackTrace();
}
}
}