java - 使用 ab 进行测试时,套接字服务器挂起,等待 BufferedReader.readline()

标签 java sockets readline serversocket apachebench

我正在制作一个基于 Java 的 Web 服务器。但当我用 ApacheBench 测试它时,它有时会停止响应。

在 Macbook Air 上:

ab -n 20000 -c 40 -d  http://localhost:1080/

在完成 16400 或更多请求后保证超时。

在 Ubuntu 桌面上

ab -n 20000 -c 1000 -d  http://localhost:1080/

大多数情况下都可以成功完成,但有时会在运行几次后停止响应。

我已经确定(使用 Eclipse),当服务器停止响应时,它正在等待 BufferedReader.readline(),我用它来读取 HTTP 请求 header 。但我不知道为什么要等。

测试代码在这里:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestServer {
    public static void main(String[] args){
        ServerSocket socket = null;

        try{
            socket = new ServerSocket(1080);
            ExecutorService pool = Executors.newFixedThreadPool(10);
            while(true){
                Socket s = socket.accept();
                pool.execute(new RequestHandler(s) );
            }
        }
        catch(Exception e){
            e.printStackTrace();
        }
        finally{
            if(null!=socket){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

class RequestHandler implements Runnable{
    final Socket s;
    public RequestHandler(Socket s) {
        this.s = s;
    }

    public void run() {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            String line = br.readLine();

            PrintWriter pw = new PrintWriter(s.getOutputStream());
            pw.print("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
            pw.print(line);
            pw.flush();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally{
            if(s!=null){
                try {
                    s.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

顺便说一句,在编写测试代码时,我发现了一些奇怪的事情

如果

BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = br.readLine();

替换为

String line = "don't read the socket";

ab 将失败并显示以下消息:“apr_socket_recv: 连接被拒绝 (111)连接被对等方重置 (104)”

但是用 Firefox 4 打开 localhost:1080 会看到“不读取套接字”的困惑情况。

最佳答案

我想知道这是否是 ApacheBench 测试的故意部分:查看当打开连接但没有发送数据时服务器的行为。据推测 ApacheBench 是开源的,因此您可以看看它在 16400 次尝试后是否会调用一些特殊行为(我打赌它会打开套接字,然后不发送请求)。

无论如何,您可能需要确保在套接字上设置显式超时,以防您的 Java 版本默认为 0(=无限)。不要假设每个客户端都会表现得完美并且总是向您发送您所期望的精确数据。

因此,作为一般规则,您需要确保您的网络服务器不会在“发生异常情况”时崩溃——网络就是这样,有时数据包/连接会随机丢失,您需要处理用它。操作系统很可能会施加限制,例如连接可以打开多长时间,这样您的服务器可能会突然看到操作系统“从它的脚下拉起地毯”。我想 ApacheBench 测试可能会模拟一些像这样的小 Sprite (这甚至可能是您在 Ubuntu 中看到的,尽管 readLine() 挂起可能是模拟不在开放连接上发送请求,正如我提到的)。

关于java - 使用 ab 进行测试时,套接字服务器挂起,等待 BufferedReader.readline(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5597385/

相关文章:

Java:希望忽略某些超出范围的行

java - 如何使用 MyBatis 从 bytea 列中获取 byte[]?

java - DPLL 算法 - 仅建议

sockets - 在服务器中的唯一一个套接字上处理多个 TCP 连接

c - 使用套接字手动建立与 ftp 服务器的连接

C 读取行函数

perl - 将 Term::ReadLine 与 Unicode 输入结合使用

java - 在Android Studio中:How I can update the column data?

c# - Unity处理来自Socket的数据流

android - 从 adb shell 使用 sqlite3 时光标键不起作用