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) == ‘\r‘) {
				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) != ‘\r‘)
					i++;
				value = raw.substring(j, i);
				map.put(key, value);
				if (i == raw.length()) {
					break;
				} else {
					j = (i += 2);
					if (raw.charAt(i) == ‘\r‘) {
						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 + "\n";
			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() + "\n";
					this.writeBytes(s.getBytes(), 0, s.length());
				}
			}
			this.out.write(‘\n‘);
		} 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() + "\n");

		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

时间: 2024-08-29 21:17:53

Java实现一个简易HTTP服务器(三)的相关文章

Java实现一个简易HTTP服务器 (二) -- 多线程

Java实现一个简易HTTP服务器 (二) -- 多线程 运行方法:新建项目后在目录下创建index.html. favicon为可选项,作为网站图标 public class Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(80); System.out.println("Server started at &quo

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

Java实现一个简易HTTP服务器(一)-- socket -----2019-9-29---------- public class Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(89); System.out.println("Server started at " + new Date() + &qu

Socket 初识 用Socket建立一个简易Web服务器

摘自<Asp.Net 本质论>作者:郝冠军 //在.Net中.system.Net命名空间提供了网络编程的大多数数据据类型以及常用操作,其中常用的类型如下:/*IPAddress 类表示一个IP地址* IPEndPoint类用来表示一个IP地址和一个端口号的组合,成为网络的端点.* System.Net.Sockets命名空间中提供了基于Socked编程的数据类型.* Socket类封装了Socked的操作.* 常见的操作:* Listen:设置基于连接通信的Socket进入监听状态,并设置等

《用Java写一个通用的服务器程序》01 综述

最近一两年用C++写了好几个基于TCP通信类型程序,都是写一个小型的服务器,监听请求,解析自定义的协议,处理请求,返回结果.每次写新程序时都把老代码拿来,修改一下协议解析部分和业务处理部分,然后就一个新的程序就诞生了.如此这般做了几回,就萌生了一个想法:是不是可以做一个通用的服务器程序,每次只要实现很少的代码就可以构建的一个新的服务器程序? 巧的是在用C++写代码的时候,我刚好碰到过一个叫做Push Framework的开源项目(在这里可以找到:www.pushframework.com),就是

用java实现一个简易编译器1-词法解析入门

本文对应代码下载地址为: http://download.csdn.net/detail/tyler_download/9435103 视频地址: http://v.youku.com/v_show/id_XMTQ3NTQwMDkxMg==.html?from=s1.8-1-1.2 技术的发展可谓是日新月异,层出不穷,但无论是炙手可热的大数据,还是火烧鸟了的人工智能,所有这些高大上的尖端科技无不建立在基础技术的根基之上.编译原理,计算机网络,操作系统,便是所有软件技术的基石.在这三根支柱中,维编

TinyWS —— 一个C++写的简易WEB服务器(三)

写在前面 代码已经托管在 https://git.oschina.net/augustus/TinyWS.git 可以用git clone下来.由于我可能会偶尔做一些修改,不能保证git 库上的代码与blog里的完全一致(实际上也不可能把所有的代码都贴在这里).另外,TinyWS是基于linux写的(ubuntu 14.10 + eclipse luna,eclipse工程我也push到了git库),故在Windows上可能无法正常编译(主要是系统调用 部分可能会不同). 前面的内容可参考上一篇

《用Java写一个通用的服务器程序》02 监听器

在一个服务器程序中,监听器的作用类似于公司前台,起引导作用,因此监听器花在每个新连接上的时间应该尽可能短,这样才能保证最快响应. 回到编程本身来说: 1. 监听器最好由单独的线程运行 2. 监听器在接到新的连接之后,处理连接的方法需要尽快返回 在Java Push Framework中,因为需要同时监听普通客户端和服务器监视服务的客户端,所以定义两种监听器:Acceptor和MonitorAcceptor. 由于两者的关于监听部分的逻辑是相同的,因此首先定义了抽象类Listener来实现了监视器

如何用Java编写一个简单的服务器和客户机

今天我要向大家介绍的是自己编写的一个比较简单的服务器和客户机程序,注意一下哦,比较简单.好了,闲话休提,砸门直入主题. 小编先从客户机和服务器的模型开始讲解.简单来说,我们实现的这种模型呢,我们每一个用户称为一个客户机,用户之间的通信之间需要一个中转,所有客户机的通信都依托于这个中转,很明显,这个中转,就是砸门的服务器了.整个模型比较简单明了,那么,接下来我们就直接进入实现阶段. 我们从实现服务器开始.Java提供了这样的一个类,ServerSocket.我们通过实例化它的方式来创建一个服务器.

如何用jsp实现一个简易计算器(三)

做这个jsp页面,主要是为了实现在同一个页面提交和接受数据的功能. 这个小程序存在很多不足,希望大家多多批评指正. <%@ page language="java" contentType="text/html;" pageEncoding="gbk"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://w