2017-01-24 2 views
1

Die Methode stopServer() der Server funktioniert einwandfrei auf Mac, Linux und UNIX-Computern, aber wenn ich versuche, unter Windows zu schließen, finde ich, dass es mindestens eine Sekunde dauert jeweils für die Sockets zu schließen wegen der Zeitüberschreitung der ServerSocket. Ich möchte, dass sie alle auf einmal geschlossen werden, so wie sie es unter Linux, Mac usw. tun, im Gegensatz zu einem, wenn ich unter Thread.join() anrufe.Thread nicht bis Thread.join() unter Windows

Server-Code

public class FileServer { 

    private ArrayList<Thread> sockets = new ArrayList<>(); 
    private ServerSocket fileServer; 

    public void startServer(int port, int maxThreads, int timeout) throws IOException { 

     fileServer = new ServerSocket(); 
     fileServer.setPerformancePreferences(1, 0, 1); 
     fileServer.bind(new InetSocketAddress(port)); 

     for (int threads = 0; threads < maxThreads; threads++) { 
      sockets.add(new Thread(new ServerInit(fileServer, timeout))); 
      System.out.println("Socket " + threads + " initialized..."); 
     } 

     for (int socket = 0; socket < sockets.size(); socket++) { 
      (sockets.get(socket)).start(); 
      System.out.println("Socket " + socket + " started!"); 
     } 
    } 

    public void stopServer() { 
     if (fileServer.isBound()) { 
      for (int thread = 0; thread < sockets.size(); thread++) { 
       sockets.get(thread).interrupt(); 
      } 
      for (int thread = 0; thread < sockets.size(); thread++) { 
       try { 
        if (sockets.get(thread).isAlive()) { 
         sockets.get(thread).join(); 
        } 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 
} 

class ServerInit implements Runnable { 
    private ServerSocket server; 
    private int timeout; 

    public ServerInit(ServerSocket server, int timeout) { 
     this.server = server; 
     this.timeout = timeout; 
    } 

    public void run() { 
     while (!Thread.interrupted()) { 
      try { 
       server.setSoTimeout(1000); 
       Socket client = server.accept(); 
       client.setSoTimeout(timeout); 
       processRequest(receiveRequest(client), client); 
       client.close(); 
      } catch (SocketTimeoutException ste) { 
      } catch (IOException io) { 
       io.printStackTrace(); 
      } 
     } 
     System.out.println("Socket closed"); 
    } 
} 

Warum ist es, dass die Fäden erfordern mich ihnen anzuschließen, bevor sie die while Schleife verlassen wird? Ich habe getestet und bin sicher, dass jeder Thread startet und dass jeder Thread ordnungsgemäß unterbrochen wird.

Auch nur ein Thread wird ordnungsgemäß gedruckt, wenn ich System.out.println() in die while Schleife legen.

EDIT

Ich bin viel mehr als bewusst, dass es für accept Timeout warten. Das soll also nur eine 1 Sekunde Timeout sein. Dies alles funktioniert perfekt auf anderen Plattformen. Ich unterbreche alle Threads und schließe mich ihnen an, um sicherzustellen, dass sie tatsächlich aufhören. Meine größte Sorge ist, warum diese Threads nicht zeitgleich ausgeführt werden, wie sie sein sollten.

+0

Wie genau stellst du dir das vor? Der Thread ist in "accept", es wird unterbrochen. Denken Sie, dass eine InterruptedException ausgelöst wird? Per Konvention löscht das Interrupt-Flag, was alles ist, was Sie überprüfen. –

+0

Es gibt nichts im Javadoc, das besagt, dass "ServerSocket.accept()" unterbrechbar ist, also warten alle Ihre Threads auf das akzeptierte Zeitlimit. Ihr Code funktioniert wie vorgesehen. Interessant, dass es auf manchen Plattformen schneller ist, aber es ist nichts falsch daran, wie es unter Windows läuft. Dein Titel ist bedeutungslos. – EJP

+0

Warum nicht eine flüchtige statische Variable (Semaphor) in der while-Schleife der 'ServerInit'-Klasse verwenden, um die Threads zu stoppen, anstatt das Interrupt-Flag zu prüfen? –

Antwort

2

Bei * nix-Betriebssystemen wird die Socket-Implementierung auf dem gesamten Weg nicht auf accept gesperrt.

für Windows, die PlainSocketImpl Klasse defines accept as synchronized:

protected synchronized void accept(SocketImpl s) throws IOException { 
    // ... 
} 

Was passiert, ist, dass accept nur zu einem Zeitpunkt von einem Thread ausgeführt wird. Das 1-Sekunden-Timeout wird erst nach der endgültigen Übernahme der Sperre vom ursprünglichen accept berücksichtigt.

Ich kann nicht sagen, ob dies beabsichtigt ist, müssen Sie in den Java-Mailinglisten fragen.