源码:
HttpServerTest类
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class HttpServerTest {
private static final int PORT = 9999;
// 获取处理器核数
private static final int COUNT = Runtime.getRuntime().availableProcessors();
// 创建线程是有消耗的,不是线程越多处理效率越高,而是要有一个合适的线程数来处理
// 处理的任务量和线程数量、CPU、内存等资源都相关
// 一般推荐处理器核数数量的线程作为固定线程池内的线程数量
private static final ExecutorService EXE = Executors.newFixedThreadPool(COUNT);
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(PORT);
while (true) {
// 一个 socket 对象代表一个客户端
// 获取客户端请求 socket 对象:阻塞方法
Socket socket = server.accept();
EXE.submit(new HttpTask(socket));
}
}
}
// Http 请求任务处理类
class HttpTask implements Runnable {
// 客户端连接
private Socket socket;
public HttpTask(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
InputStream is = null;
InputStreamReader isr = null;
BufferedReader br = null;
OutputStream os = null;
// 输出流的包装
// 打印
PrintWriter pw = null;
try {
try {
// 获取客户端请求数据:输入流
is = socket.getInputStream();
// 转换流,转换成字符流
isr = new InputStreamReader(is, "UTF-8");
// 在缓冲字符流中读取,提高效率
br = new BufferedReader(isr);
RequestTest requestTest = new RequestTest(); // 初始化请求对象
// 请求数据的解析:http 协议报的解包
// 1.解析请求行(第一行):method url version
String requestLine = br.readLine();
String[] requestLines = requestLine.split(" ");
requestTest.setMethod(requestLines[0]);
// 可能为 http://Localhost:9999/xxx?username=stu&password=123
// ?问号前的放到 url 里面去,?问号之后的放到请求参数里面去
String url = requestLines[1];
if (url.contains("?")) {
String parameters = url.substring(url.indexOf("?") + 1);
requestTest.parseParameters(parameters);
url = url.substring(0, url.indexOf("?"));
}
requestTest.setUrl(url);
requestTest.setVersion(requestLines[2]);
// 2.解析请求头:key : value 每个换行,以空行作为结尾
String header;
// 通过流来读取
while ((header = br.readLine()) != null
&& header.length() != 0) {
// 既不是空行也不是空值
// 代表从0到冒号:结束
String key = header.substring(0, header.indexOf(":"));
String value = header.substring(header.indexOf(":") + 1);
// trim() 方法去掉空格
requestTest.addHeader(key, value.trim());
}
// POST请求,需要根据请求头 Content-Length 获取请求体的长度
if ("POST".equals(requestTest.getMethod())) {
String len = requestTest.getHeader("Content-Length");
if (len != null) {
int l = Integer.parseInt(len);
char[] chars = new char[l];
br.read(chars, 0, l);
// 请求参数格式:username=stu&password=123
String requestBody = new String(chars);
requestTest.parseParameters(requestBody);
}
}
System.out.println(requestTest);
// 获取客户端输出流,返回响应数据
os = socket.getOutputStream();
// PrintWriter 是打印流,需要发送到缓冲区的,
// 所以需要在缓冲区里自动刷新一下
pw = new PrintWriter(os, true);
// http://Localhost:9999/302/111
// 只找 /302/111,所以要去掉前面的部分
if ("/302".equals(requestTest.getUrl())) {
pw.println("HTTP/1.1 302 重定向");
pw.println("Content-Type:text/html;charset=utf-8");
pw.println("Location: http://www.baidu.com");
}
} finally {
// 反向关闭
if (br != null) {
br.close();
}
if (isr != null) {
isr.close();
}
if (is != null) {
is.close();
}
if (pw != null) {
pw.close();
}
if (os != null) {
os.close();
}
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
RequestTest类:
import java.util.HashMap;
import java.util.Map;
public class RequestTest {
private String method; // 请求方法
private String url; // 请求路径
private String version; // http 版本号
private Map<String, String> headers = new HashMap<>(); // 保存请求头
private Map<String, String> parameters = new HashMap<>(); // 保存请求参数
// 添加请求头
public void addHeader(String key, String value) {
headers.put(key, value);
}
// 获取某个请求头
public String getHeader(String key) {
return headers.get(key);
}
@Override
public String toString() {
return "RequestTest{" +
"\n method='" + method + '\'' +
",\n url='" + url + '\'' +
",\n version='" + version + '\'' +
",\n headers=" + headers +
",\n parameters=" + parameters +
'}';
}
// 解析请求参数 key1=value1&key2=value2
public void parseParameters(String parameters) {
// 暂时没有考虑参数的判断
String[] ps = parameters.split("&");
for (String p : ps) {
String[] array = p.split("=");
addParameter(array[0], array[1]);
}
}
// 添加请求参数
public void addParameter(String key, String value) {
parameters.put(key, value);
}
// 获取请求参数
public String getParameter(String key) {
return parameters.get(key);
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public Map<String, String> getHeaders() {
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
public Map<String, String> getParameters() {
return parameters;
}
public void setParameters(Map<String, String> parameters) {
this.parameters = parameters;
}
}