[英]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.