哈,本人现在大三还在为了学业奋斗,这些天很累,好多实验,也快要考试了,自己还负责的web重构和app开发任务还是比较重的。小菜小菜在这些时间里面进步也是蛮多的,为什么要写web服务器呢?不仅仅是因为比较酷哈,这也是我们的课程要求撒。当然要写就要写的比较好所以自己对这个实验也是蛮有兴趣的 。
服务器能够接受来自浏览器发来的的get的静态文件的请求,服务器可以处理来自浏览器的多次请求,因为这个服务器写出来花的时间并不长所以功能也想对来说简单些,不过小菜在日后会不断的完善期功能,当然也会参考Servlet规范写出支持Servlet的容器,不过这些都是后话了先看下面贴出代码并解释其过程:
这个是我的工程结构
1,程序入口:
package com.zdx.sever;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.zdx.domain.Request;
import com.zdx.domain.Response;
/**
* 这里使用到了线程池来处理客户端发的多次请求,以节约系统资源,减少线程的创建从而提高系统性能
* @author zdx
*
*/
public class MainServer {
private final int port = 8091;
// 线程池维护的最小线程数量
private static int corePoolSize = 3;
// 线程池维护的最大线程数
private static int maximumPoolSize = 10;
// 线程池维护线程所允许的空闲时间
private static int keepAliveTime=10;
// 线程池维护线程所允许的空闲时间的单位
private static TimeUnit timeUnit = TimeUnit.SECONDS;
// 线程池所使用的缓冲队列
private BlockingQueue<Runnable> blockingQueue;
// 线程池
private ExecutorService executor;
public MainServer() {
blockingQueue = new ArrayBlockingQueue<>(5);
//创建线程池对象
this.executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, timeUnit, blockingQueue);
}
/**
*
*处理请求
*
*/
public void dealRequest() {
try {
ServerSocket serverSocket = new ServerSocket(port);
Socket socket = null;
InetAddress inetAddress;
InputStream inputStream = null;
OutputStream outputStream = null;
while (true) {
//阻塞
socket = serverSocket.accept();
//创建Request对象
inputStream = socket.getInputStream();
inetAddress = socket.getInetAddress();
Request request=new Request(inputStream, inetAddress);
//创建Response;
outputStream = socket.getOutputStream();
Response response=new Response(outputStream);
//创建处理线程
HandlerRunnable handlerRunnable=new HandlerRunnable(request, response);
//将线程提交到线程池中进行处理
this.executor.submit(handlerRunnable);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
MainServer mainServer=new MainServer();
mainServer.dealRequest();
}
}
2,下面是Request类,其中对请求做了解析和封装处理
package com.zdx.domain;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
import com.zdx.util.RequestUtil;
public class Request {
private String requestType;
private String requestUrl;
private InputStream inputStream;
private InetAddress inetAddress;
private Map<String, Object> paramters;
public Request(InputStream inputStream, InetAddress inetAddress) {
this.inputStream = inputStream;
this.inetAddress = inetAddress;
this.paramters=new HashMap<String,Object>();
parseRequest();
}
private void parseRequest() {
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(inputStream));
String msg;
try {
msg = bufferedReader.readLine();
while (msg == null) {
return;
}
//获得请求类型
String requestType = RequestUtil.getRequestType(msg);
if (requestType.equals("GET")) {
this.requestType = "GET";
} else {
this.requestType = "POST";
}
// 设置请求的资源
this.requestUrl = RequestUtil.getRequestFileName(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String getRequestType() {
return requestType;
}
public void setRequestType(String requestType) {
this.requestType = requestType;
}
public String getRequestUrl() {
return requestUrl;
}
public void setRequestUrl(String requestUrl) {
this.requestUrl = requestUrl;
}
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
}
3,设置Resopnse类;
package com.zdx.domain;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;
public class Response {
private OutputStream outputStream;
private BufferedWriter writer;
private Map<String, Object> paramter;
public Response(OutputStream outputStream) {
this.outputStream=outputStream;
this.writer=new BufferedWriter(new OutputStreamWriter(outputStream));
this.paramter = new HashMap<String, Object>();
}
public void output(byte[] datas) throws IOException {
outputStream.write(datas);
}
public OutputStream getOutputStream() {
return outputStream;
}
public void setOutputStream(OutputStream outputStream) {
this.outputStream = outputStream;
}
public Map<String, Object> getParamter() {
return paramter;
}
public void setParamter(Map<String, Object> paramter) {
this.paramter = paramter;
}
public Object addAttribute(String key, Object value) {
return this.paramter.put(key, value);
}
public Object setAttribute(String key, Object value) {
return this.paramter.put(key, value);
}
public Object removeAttribute(String key) {
return this.paramter.remove(key);
}
public void closeWriter() throws IOException{
this.writer.close();
}
public void closeOutPutStream() throws IOException{
this.outputStream.close();
}
}
4,具体的请求处理线程类:
package com.zdx.sever;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import com.zdx.domain.Request;
import com.zdx.domain.Response;
import com.zdx.util.Constant;
import com.zdx.util.RequestUtil;
public class HandlerRunnable implements Runnable {
private Request request;
private Response response;
public HandlerRunnable(Request request, Response response) {
this.request = request;
this.response = response;
}
@Override
public void run() {
try {
requestHandler();
} catch (IOException e) {
e.printStackTrace();
}
}
private void requestHandler() throws IOException {
String requestType = request.getRequestType();
if (requestType.equals("GET")) {
String fileName = request.getRequestUrl();
String filePath = Constant.WEB_ROOT + fileName;
System.out.println(filePath);
// GET the OutputSteam object
OutputStream outputStream = response.getOutputStream();
// 进行文件的读取
File file = new File(filePath);
if (file.exists()) {
FileInputStream fileInputStream = new FileInputStream(file);
byte[] bufferByte = new byte[1024];
int read = fileInputStream.read(bufferByte);
while (read != -1) {
outputStream.write(bufferByte, 0, read);
read = fileInputStream.read(bufferByte, 0, 1024);
}
} else {
outputStream.write("404!! can not find the file".getBytes());
}
outputStream.flush();
outputStream.close();
System.out.println("over!!");
}
}
public Request getRequest() {
return request;
}
public void setRequest(Request request) {
this.request = request;
}
}
这几行代码就可以做到了下面是程序运行后的一个效果图:
看上面有图片有文字,哈哈,并可以处理多次请求,但是resopnse的相应头和其他信息都还没有做不过以后会做的,此容器的后续开发回持续更新,请前辈们给点意见指导哈