写个web容器是不是很酷? 博客分类: Java Web java webweb 容器web服务器
程序员文章站
2024-03-16 11:11:16
...
哈,本人现在大三还在为了学业奋斗,这些天很累,好多实验,也快要考试了,自己还负责的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的相应头和其他信息都还没有做不过以后会做的,此容器的后续开发回持续更新,请前辈们给点意见指导哈