Java实现一个简易HTTP服务器(三)

从InputStream读取数据,构造Request。Request包含Http请求的参数。

public class Request {
	public String method; // 请求方法
	public String path; // 请求路径
	public String portal; // 协议名称
	public Map<String, String> map; // 请求头中的附加参数
	public String payload; // 请求体

	private int BUFFER_LEN = 10240;

	public Request(InputStream in) throws IOException {
		byte[] buf = new byte[BUFFER_LEN];
		int len = in.read(buf);
		String reqString = new String(buf, 0, len);
		String raw = reqString;
		int i = 0, j = 0;

		// 获取请求方式
		for (; i < raw.length(); i++)
			if (raw.charAt(i) == ' ') {
				this.method = raw.substring(j, i);
				break;
			}
		j = ++i;
		// 获取请求路径
		for (; i < raw.length(); i++)
			if (raw.charAt(i) == ' ') {
				this.path = raw.substring(j, i);
				break;
			}
		j = ++i;
		// 获取协议版本
		for (; i < raw.length(); i++)
			if (raw.charAt(i) == '
') {
				this.portal = raw.substring(j, i);
				break;
			}
		j = (i += 2);

		this.map = new HashMap<String, String>();
		String key = "", value = "";
		while (i < raw.length()) {
			if (raw.charAt(i) != ':') {
				i++;
			} else {
				key = raw.substring(j, i);
				j = (i += 2);
				while (i != raw.length() && raw.charAt(i) != '
')
					i++;
				value = raw.substring(j, i);
				map.put(key, value);
				if (i == raw.length()) {
					break;
				} else {
					j = (i += 2);
					if (raw.charAt(i) == '
') {
						payload = raw.substring(i + 2);
					}
				}
			}

		}

	}

	@Override
	public String toString() {
		return "Request [method=" + method + ", path=" + path + ", portal=" + portal + ", map=" + map + ", payload="
				+ payload + "]";
	}

}

Response 向输出流中写入参数。类中定义了部分用到的方法。

package cdbb.httpd;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class Response {
	private OutputStream out;

	public String portal;
	public String status;
	public String statusDescribe;
	public Map<String, String> map;

	public Response(OutputStream out, String portal, String status, String statusDescribe) {
		this.out = out;
		this.portal = portal;
		this.status = status;
		this.statusDescribe = statusDescribe;
	}

	public void writeHeaderAndBody(byte[] b, int off, int len) {
		this.writeHeader();
		this.writeBytes(b, off, len);
	}

	public void addHeader(String key, String value) {
		this.map.put(key, value);
	}

	public void delHeader(String key) {
		if (this.map.containsKey(key))
			this.map.remove(key);
	}

	public void editHeader(String key, String value) {
		if (this.map.containsKey(key))
			this.map.replace(key, value);
	}

	public void writeHeader() {
		try {
			String tmp = portal + " " + status + " " + statusDescribe + "
";
			this.writeBytes(tmp.getBytes(), 0, tmp.length());
			if (map != null) {
				Iterator<Map.Entry<String, String>> entries = map.entrySet().iterator();
				while (entries.hasNext()) {
					Entry<String, String> entry = entries.next();
					String s = entry.getKey() + " " + entry.getValue() + "
";
					this.writeBytes(s.getBytes(), 0, s.length());
				}
			}
			this.out.write('
');
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void writeBytes(byte[] b, int off, int len) {
		try {
			this.out.write(b, off, len);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

在浏览器和服务端建立起tcp连接后获得socket,一个连接对应一个socket。socket调用Request和Response处理请求

package cdbb.httpd;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Handler implements Runnable {
	public Socket socket;

	public Handler(Socket socket) {
		this.socket = socket;
	}

	@Override
	public void run() {
		try {
			InputStream in = socket.getInputStream();
			Request req = new Request(in);
			System.out.println(req);

			if ("/".equals(req.path)) {
				req.path = "index.html";
			}
			if ("/favicon.ico".equals(req.path)) {
				req.path = "favicon.ico";
			}
			File file = new File(req.path);
			InputStream fin = new FileInputStream(file);
			int len = 0;
			byte[] buf = new byte[1024];

			OutputStream out = socket.getOutputStream();
			Response res = new Response(out, "HTTP/1.1", "200", "OK");
			res.writeHeader();
			while ((len = fin.read(buf)) > 0)
				res.writeBytes(buf, 0, len);

			socket.close();
			fin.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

建立和浏览器的连接,并采用线程池技术调用Handler进行具体的处理

package cdbb.httpd;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author cdbb
 */
public class Server {

	public static void main(String[] args) throws IOException {
		ServerSocket serverSocket = new ServerSocket(80);
		System.out.println("Server started at " + new Date() + "
");

		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 5, 200, TimeUnit.MILLISECONDS,
				new ArrayBlockingQueue<Runnable>(5), Executors.defaultThreadFactory(),
				new ThreadPoolExecutor.AbortPolicy());
		try {
			while (true) {
				// 通信socket的获得
				Socket socket = serverSocket.accept();
				threadPoolExecutor.execute(new Handler(socket));
			}
		} catch (Exception e) {
			e.printStackTrace();
			serverSocket.close();
		}

	}
}

原文地址:https://www.cnblogs.com/cdbb/p/12558169.html