簡體   English   中英

使用Ab測試時,套接字服務器掛起,等待BufferedReader.readline()

[英]Socket server hang when testing with ab, waiting BufferedReader.readline()

我正在制作一個基於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請求標頭。 但是我不知道為什么要等待。

測試代碼在這里:

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(=無限)。 不要以為每個客戶都會表現得很好,並且總是向您准確發送您期望的數據。

因此,作為一般規則,如果“發生異常事件”,您需要確保Web服務器不會掉下來-網絡就是這樣,有時數據包/連接會被隨機丟棄,您需要對其進行處理。 操作系統可能會對例如可以打開連接的時間施加限制,因此您的服務器可能會突然看到操作系統發出的“從腳下拉出的地毯”。 我想象ApacheBench測試可能會模擬一些這樣的gremlins(甚至可能是您在Ubuntu中看到的東西,盡管readLine()掛起可能是模擬的,它不像我提到的那樣在打開的連接上發送請求)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM