2011-04-08 3 views
0

Je crée un serveur Web basé sur Java. Mais quand je le teste avec ApacheBench, il arrête parfois de répondre.Le serveur socket se bloque lors d'un test avec ab, en attente BufferedReader.readline()

Sur un Macbook Air:

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

est garanti à délai d'attente après 16400 ou plusieurs demandes ont été faites.

Sur le bureau Ubuntu

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

pourrait faire avec succès la plupart du temps, mais parfois cesser de répondre après plusieurs passages.

J'ai identifié (à l'aide d'Eclipse) que lorsque le serveur cesse de répondre, il attend BufferedReader.readline() que je l'utilise pour lire l'en-tête de la requête HTTP. Mais je n'ai aucune idée de pourquoi ça l'attend.

Code d'essai est ici:

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(); 
       } 
      } 
     } 
    } 
} 

BTW, lors de l'écriture du code de test, j'ai trouvé quelque chose d'autre étrange

Si

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

est remplacé par

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

ab va échouer avec un tel message: "apr_socket_recv: Connexion refusée (111) Connexion réinitialisée par le pair (104)"

Mais localhost ouvert: 1080 avec Firefox 4 verra apparaître le message "ne pas lire le socket" .

+1

Vous ne fermez pas vos prises en cas d'exception. Vous devriez changer pour que 's.close' soit dans un bloc finally. (Je ne sais pas si c'est le problème, mais ça aiderait à éclaircir les choses) –

+0

N'aidant pas dans ce cas, mais je pense que vous avez raison. Code mis à jour. – CQD

Répondre

1

Je me demande si cela fait délibérément partie du test ApacheBench: pour voir comment se comporte votre serveur lorsqu'une connexion est ouverte mais pas de données envoyées. On peut supposer qu'ApacheBench est open source donc vous pouvez jeter un coup d'oeil à voir s'il invoque un comportement spécial (mon pari est sur l'ouverture de la socket et ne pas envoyer une requête) après 16400 tentatives.

Dans tous les cas, vous voulez probablement vous assurer que vous définissez un délai d'attente explicite sur le socket au cas où votre version de Java est par défaut 0 (= infini). Ne présumez pas que chaque client se comportera parfaitement et vous enverra toujours les données que vous attendez. En règle générale, vous devez vous assurer que votre serveur Web ne tombera pas si "quelque chose d'inhabituel arrive" - ​​les réseaux sont comme ça, et parfois les paquets/connexions seront perdus au hasard et vous devrez Faites avec. Les systèmes d'exploitation peuvent très bien imposer des limites, par ex. Combien de temps une connexion peut-elle être ouverte et que votre serveur peut soudainement voir le "tapis tiré de ses pieds" par le système d'exploitation. J'imagine que le test ApacheBench peut simuler quelques gremlins comme celui-ci (qui pourrait même être ce que vous voyez dans Ubuntu, bien que la suspension de readLine() soit probablement une simulation de ne pas envoyer de requête sur une connexion ouverte.

Questions connexes