`
come_for_dream
  • 浏览: 116579 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

写个web容器是不是很酷?

阅读更多

哈,本人现在大三还在为了学业奋斗,这些天很累,好多实验,也快要考试了,自己还负责的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的相应头和其他信息都还没有做不过以后会做的,此容器的后续开发回持续更新,请前辈们给点意见指导哈

  • 大小: 35.3 KB
  • 大小: 913 KB
6
5
分享到:
评论
13 楼 残云cruel 2015-06-06  
呀,界面挺好看的啊,嗯呢 不错不错。年轻人 有前途,值得栽培
12 楼 come_for_dream 2015-04-17  
yzsunlight 写道
代码可否共享

https://github.com/zdxit/WebServer
11 楼 yzsunlight 2015-04-17  
代码可否共享
10 楼 come_for_dream 2015-04-16  
yangshangchuan 写道
cool! i mean awful.

thanks any way
9 楼 yangshangchuan 2015-04-16  
cool! i mean awful.
8 楼 come_for_dream 2015-04-16  
killko 写道
很不错!

socket那里可以尝试用nio,效率会更高;
注意一下HTTP的回应的状态码,例如你代码里的404,应该在header里体现出来

这样,好的,我改进一下
7 楼 come_for_dream 2015-04-16  
DreamRoute 写道
楼主才大三就有这理解,很不错,不过如果楼主认为这几行代码就叫做所谓的Web容器的话,那你对Web“容器”的理解未免就有些狭隘了。

恩恩,后续根绝Servlet规范加入支持Servlet的功能才能叫容器,谢谢指点 
6 楼 DreamRoute 2015-04-16  
楼主才大三就有这理解,很不错,不过如果楼主认为这几行代码就叫做所谓的Web容器的话,那你对Web“容器”的理解未免就有些狭隘了。
5 楼 killko 2015-04-16  
很不错!

socket那里可以尝试用nio,效率会更高;
注意一下HTTP的回应的状态码,例如你代码里的404,应该在header里体现出来
4 楼 Tyrion 2015-04-16  
大三的写成这样还不错了已经。
3 楼 come_for_dream 2015-04-16  
kknd97 写道
结构设计的很优雅,流程清晰,思路简介,非常非常好。
作为大三的学生能有如此的功底和基础知识,非常好。
继续努力!

谢谢前辈
2 楼 kknd97 2015-04-16  
结构设计的很优雅,流程清晰,思路简介,非常非常好。
作为大三的学生能有如此的功底和基础知识,非常好。
继续努力!
1 楼 wwwcomy 2015-04-16  
en ....

Tomcat雏形...

相关推荐

Global site tag (gtag.js) - Google Analytics