一、目标
诸如tomcat等web服务器中间件简化了我们web的开发成本,但有时候我们或许并不需要这么一个完备的服务器,只是希望做一个简单地处理或者做特殊用途的服务器。
本文将提供一个HTTP的服务器示例,采用Java的ServerSocket进行编码。随着计算机硬件的提升,以及Java地不断优化,使用Java网络编程实现web服务器在实际性能上已经开始可以跟C进行竞争。
二、代码示例
以下代码分为两块:
1)HttpServer:主要包含一个ServerSocket,用于接收客户端请求。并通过线程池将请求从主线程剥离,分散到各个线程中去处理;
2)RequestHandler:实现了Runnable接口,将获取一个线程来处理各个请求;流的读取和响应遵循HTTP协议。
注意:编写Http服务器和一般的socket程序并没有太大不同,但是你需要遵循HTTP协议,这样对于采用HTTP协议的客户端或者其它服务器就可以直接进行HTTP请求来通讯。
HttpServer
import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.util.concurrent.*;/** * Http服务器端示例,端口设置为8080,编码设置为UTF-8 * @author lay * @date 2019-01-01 */public class HttpServer { ???private static final int port = 8080; ???/** ????* 启动HTTP服务器 ????*/ ???public void start() throws IOException { ???????// 初始化线程池 ???????ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); ???????// 初始化服务器socket ???????ServerSocket serverSocket = new ServerSocket(port); ???????System.out.println("ServerSocket启动完成"); ???????while (true) { ???????????// 阻塞等待socket连接 ???????????System.out.println("等待socket"); ???????????Socket socket = serverSocket.accept(); ???????????// 提交至线程池处理 ???????????executor.submit(new RequestHandler(socket)); ???????????System.out.println("提交线程池处理请求"); ???????} ???} ???public static void main(String[] args) { ???????try { ???????????new HttpServer().start(); ???????} catch (IOException e) { ???????????throw new RuntimeException(e); ???????} ???}}
RequestHandler
import java.io.*;import java.net.Socket;/** * 请求处理类 * @author lay * @date 2019-01-01 */public class RequestHandler implements Runnable { ???/** ????* HTTP响应头 ????*/ ???private static final String response = "http/1.1 200 ok"; ???private static final String splitStr = "\r\n"; ???private Socket ????????socket; ???private BufferedReader reader; ???private BufferedWriter writer; ???public RequestHandler(Socket socket) throws IOException { ???????this.socket = socket; ???????this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); ???????this.writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); ???} ???/** ????* 响应结果 ????* @param content 响应内容 ????* @throws IOException IO异常抛出 ????*/ ???public void sendResponse(String content) throws IOException { ???????writer.write(String.format("%s%s", response, splitStr)); ???????writer.write(splitStr); ???????writer.write(content); ???} ???/** ????* 获得请求 ????* @return 请求文本 ????* @throws IOException IO异常抛出 ????*/ ???public String getRequest() throws IOException { ???????StringBuilder stringBuilder = new StringBuilder(); ???????String ???????line; ???????while ((line = reader.readLine()) != null) { ???????????stringBuilder.append(line); ???????????stringBuilder.append(splitStr); ???????????// 空字符串 ???????????if (line.isEmpty()) { ???????????????break; ???????????} ???????} ???????System.out.println("request:\r\n" + stringBuilder); ???????return stringBuilder.toString(); ???} ???@Override ???public void run() { ???????try { ???????????String request = getRequest(); ???????????// 这里直接把请求数据响应回去 ???????????sendResponse(request); ???????????writer.flush(); ???????} catch (IOException e) { ???????????e.printStackTrace(); ???????} finally { ???????????try { ???????????????reader.close(); ???????????} catch (IOException e) { ???????????????e.printStackTrace(); ???????????} ???????????try { ???????????????writer.close(); ???????????} catch (IOException e) { ???????????????e.printStackTrace(); ???????????} ???????????try { ???????????????socket.close(); ???????????} catch (IOException e) { ???????????????e.printStackTrace(); ???????????} ???????} ???}}
请求处理器这里直接将请求的HTTP内容返回回去了,如果你使用浏览器请求8080端口,你会看到如下内容:
不过浏览器会默认请求一个icon,所以针对一个URL地址会有两个请求
你可以在ico请求的时候返回一个二进制的ico文件流,它将显示在浏览器的tab上。
扩展点:
1)我们可以像tomcat一样去支持Java Servlet API
2)支持如GET、POST、PUT、DELETE等restful请求
3)将程序配置进行XML配置
4)增加管理界面
5)请求跟踪处理
6)缓存、非阻塞IO、通道来增加性能
二、如何编写一个简单的HTTP服务器
原文地址:https://www.cnblogs.com/lay2017/p/10206505.html