写在前面

本文通过socket编程来实现一个简单的HttpServer。
1:单线程版本
我们使用单线程来实现一个HttpServer,如下:
package dongshi.daddy.io.httpserver;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class HttpServer1 {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(8801);
        while (true) {
            try {
                Socket socket = serverSocket.accept();
                service(socket);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    private static void service(Socket socket) {
        String body = "hello,nio1";
        try {
            System.out.println("request come!!!");
            // 模拟耗时操作
            Thread.sleep(100);
            PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
            // 模拟http的响应,分为响应头和响应体(对象的组成也是头和体,不过是对象头和对象体),其中响应头和响应体通过换行符分割
            /*** 响应头开始 ***/
            printWriter.println("HTTP/1.1 200 OK");
            printWriter.println("Content-Type:text/html;charset=utf-8");
            // 注意一定要有该内容告知客户端响应体的长度,不然客户端将无法正常读取数据
            printWriter.println("Content-Length:" + body.getBytes().length);
            // 空行结束响应头
            printWriter.println();
            /*** 响应头结束 ***/
            /*** 响应体开始 ***/
            printWriter.write(body);
            /*** 响应体结束 ***/
//            printWriter.flush();
            printWriter.close();
            socket.close();
        } catch (Exception e) {
        }
    }
}
curl:
C:\WINDOWS\system32>curl http://localhost:8801
hello,nio1
superbenchmark,即sb压力测试:
D:\>sb -u http://localhost:8801 -c 40 -N 10
Starting at 2023/5/31 星期三 15:48:15
[Press C to stop the test]
92      (RPS: 6.4)
---------------Finished!----------------
Finished at 2023/5/31 星期三 15:48:29 (took 00:00:14.5303526)
102     (RPS: 7)                        Status 200:    102
RPS: 9 (requests/second)
Max: 4471ms
Min: 194ms
Avg: 3580.1ms
  50%   below 4380ms
  60%   below 4389ms
  70%   below 4400ms
  80%   below 4405ms
  90%   below 4415ms
  95%   below 4418ms
  98%   below 4418ms
  99%   below 4420ms
99.9%   below 4471ms
130     (RPS: 9)
从RPS: 9 (requests/second)可以看到处每秒请求数是9,接下来看下多线程版本的性能表现。
2:多线程版本
我们使用多线程来实现一个HttpServer,如下:
package dongshi.daddy.io.httpserver;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class HttpServer2 {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(8802);
        while (true) {
            try {
                Socket socket = serverSocket.accept();
//                service(socket);
                new Thread(() -> {
                    service(socket);
                }).start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    private static void service(Socket socket) {
        String body = "hello,nio1";
        try {
            System.out.println("request come!!!");
            Thread.sleep(100);
            PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
            // 模拟http的响应,分为响应头和响应体(对象的组成也是头和体,不过是对象头和对象体),其中响应头和响应体通过换行符分割
            /*** 响应头开始 ***/
            printWriter.println("HTTP/1.1 200 OK");
            printWriter.println("Content-Type:text/html;charset=utf-8");
            // 注意一定要有该内容告知客户端响应体的长度,不然客户端将无法正常读取数据
            printWriter.println("Content-Length:" + body.getBytes().length);
            // 空行结束响应头
            printWriter.println();
            /*** 响应头结束 ***/
            /*** 响应体开始 ***/
            printWriter.write(body);
            /*** 响应体结束 ***/
//            printWriter.flush();
            printWriter.close();
            socket.close();
        } catch (Exception e) {
        }
    }
}
superbenchmark,即sb压力测试:
D:\>sb -u http://localhost:8802 -c 40 -N 10
Starting at 2023/5/31 星期三 15:49:33
[Press C to stop the test]
3478    (RPS: 253.3)
---------------Finished!----------------
Finished at 2023/5/31 星期三 15:49:47 (took 00:00:13.9143063)
Status 200:    3444
Status 303:    34
RPS: 308.8 (requests/second)
Max: 315ms
Min: 101ms
Avg: 112.8ms
  50%   below 108ms
  60%   below 108ms
  70%   below 109ms
  80%   below 110ms
  90%   below 114ms
  95%   below 124ms
  98%   below 218ms
  99%   below 220ms
99.9%   below 238ms
RPS 是308.8,明显好于单线程版本,但是这里是每次创建线程,而创建线程本身因为涉及到底层的操作,所以比较重,我们再改为线程池的版本看下效果。
3:线程池版本
package dongshi.daddy.io.httpserver;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class HttpServer3 {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(8803);
//        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
        ExecutorService executorService = Executors.newFixedThreadPool(50);
        while (true) {
            try {
                Socket socket = serverSocket.accept();
//                service(socket);
                executorService.execute(() -> service(socket));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    private static void service(Socket socket) {
        String body = "hello,nio1";
        try {
            System.out.println("request come!!!");
            Thread.sleep(100);
            PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
            // 模拟http的响应,分为响应头和响应体(对象的组成也是头和体,不过是对象头和对象体),其中响应头和响应体通过换行符分割
            /*** 响应头开始 ***/
            printWriter.println("HTTP/1.1 200 OK");
            printWriter.println("Content-Type:text/html;charset=utf-8");
            // 注意一定要有该内容告知客户端响应体的长度,不然客户端将无法正常读取数据
            printWriter.println("Content-Length:" + body.getBytes().length);
            // 空行结束响应头
            printWriter.println();
            /*** 响应头结束 ***/
            /*** 响应体开始 ***/
            printWriter.write(body);
            /*** 响应体结束 ***/
//            printWriter.flush();
            printWriter.close();
            socket.close();
        } catch (Exception e) {
        }
    }
}
superbenchmark,即sb压力测试:
D:\>sb -u http://localhost:8803 -c 40 -N 10
Starting at 2023/5/31 星期三 15:59:52
[Press C to stop the test]
3422    (RPS: 248.7)
3428    (RPS: 248.9)                    ---------------Finished!----------------
3428    (RPS: 248.9)                    Finished at 2023/5/31 星期三 16:00:06 (took 00:00:13.8633252)
3466    (RPS: 251.6)                    Status 200:    3430
Status 303:    36
RPS: 314.4 (requests/second)
Max: 256ms
Min: 101ms
Avg: 112.9ms
  50%   below 107ms
  60%   below 108ms
  70%   below 108ms
  80%   below 109ms
  90%   below 114ms
  95%   below 126ms
  98%   below 217ms
  99%   below 232ms
99.9%   below 255ms
RPS 是314.4,好于多线程版本的308.8。
写在后面
参考文章列表
SuperBenchmarker(简称“sb“)压力测试工具详解 。
在windows上通过choco安装superbenchmarker进行压测 。



















