能自己实现一个简单的 HTTP 服务器,还有些小激动的。
本简单 HTTP Server 实现给客户端返回 HTML 文本和二进制文件(图片),
啥也不说了,直接上码吧:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
class HttpRequestHandler implements Runnable {
private Socket socket;
private String basePath;
public HttpRequestHandler(Socket socket, String basePath) {
this.socket = socket;
this.basePath = basePath;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
BufferedReader reader = null;
// 向客户端输出内容
PrintStream printStream = null;
InputStream in = null;
BufferedReader br = null;
try {
// 在 socket 上获得输入流,使用默认字符集的 InputStreamReader
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 读取 HTTP 报文的请求行
String header = reader.readLine();
System.out.println("thread name: " + threadName + ", HTTP 报文请求行: " + header);
// 读取HTTP请求报文的起始行,并根据空格分割开,存入数组,得到请求的资源
// 由相对路径计算出绝对路径
String filePath = this.basePath + header.split(" ")[1];
printStream = new PrintStream(socket.getOutputStream(), true);
// 如果请求资源的后缀为jpg 或者 ico,则读取资源并输出
if (filePath.endsWith("jpg") || filePath.endsWith("ico")) {
System.out.println("thread name: " + threadName + ", filePath: " + filePath);
in = new FileInputStream(filePath);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int i;
while ((i = in.read(buff)) != -1) {
baos.write(buff, 0, i);
}
byte[] array = baos.toByteArray();
// 设置响应报文
printStream.println("HTTP/1.1 200 OK");
printStream.println("Server: MyServer");
printStream.println("Content-Type: image/jpeg");
printStream.println("Content-Length: " + array.length);
// 根据 HTTP 协议, 空行将结束头信息
printStream.println();
printStream.write(array);
} else if (filePath.endsWith("html")) {
// 客户端请求的是 html 文件
br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));
printStream.println("HTTP/1.1 200 OK");
printStream.println("Server: MyServer");
printStream.println("Content-Type: text/html; charset=UTF-8");
printStream.println();
String line;
while ((line = br.readLine()) != null) {
printStream.println(line);
}
}
printStream.flush();
} catch (Exception ex) {
ex.printStackTrace();
printStream.println("HTTP/1.1 500");
printStream.println();
printStream.flush();
} finally {
this.close(br, in, reader, socket, printStream);
}
}
private void close(Closeable... closeables) {
if (closeables != null) {
for (Closeable closeable : closeables) {
try {
if (closeable != null) {
closeable.close();
}
} catch (Exception e) {
}
}
}
}
}
public class MySimpleHttpServer {
// 处理 HttpRequest 的线程池
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
/**
* SimpleHttpServer 的根路径
*/
private String basePath;
/**
* 服务监听端口
*/
private int port = 8080;
public void start() throws Exception {
System.out.println("start at " + port + ", basePath: " + this.basePath);
// serverSocket 接受客户端的请求
ServerSocket serverSocket = new ServerSocket(port);
Socket socket;
/**
* 服务端 serverSocket 接受客户端请求,并创建客户端 socket 对象
*/
while ((socket = serverSocket.accept()) != null) {
/**
* 接收一个客户端Socket,生成一个HttpRequestHandler,放入线程池队列
*/
executor.execute(new HttpRequestHandler(socket, this.basePath));
}
serverSocket.close();
}
public void setBasePath(String basePath) {
if (basePath != null && new File(basePath).exists() &&
new File(basePath).isDirectory()) {
this.basePath = basePath;
}
}
public void setPort(int port) {
if (port > 0) {
this.port = port;
}
}
}
运行server:
public class ServerStart {
public static void main(String[] args) throws Exception {
MySimpleHttpServer httpServer = new MySimpleHttpServer();
httpServer.setBasePath("/data/simpleHttpServer");
httpServer.start();
}
}
写一个 HTML 页面测试一下吧:
// index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel=”icon” href=”favicon.ico” mce_href=”favicon.ico” type=”image/x-icon”>
<title>simple server test</title>
</head>
<body>
文档内容......
<h1>第一张图片</h1>
<img src="1.jpg" align="middle" />
<h1>第二张图片</h1>
<img src="2.jpg" align="middle" />
<h1>第三张图片</h1>
<img src="3.jpg" align="middle" />
</body>
</html>
将 index.html
、1.jpg
等资源放到basePath
下,然后在浏览器的地址栏里输入:http://127.0.0.1:8080/index.html,然后就看到这个奇妙的网页了:
浏览器并发的请求,因为有了多线程,这个简单的 HTTP Server 的吞吐量也还可以的,响应时间也很小。
参考: 用java实现的一个简单web服务器程序
java实现简单的http服务器
HTTP头部详解及使用Java套接字处理HTTP请求