Come posso interrompere un metodo Accept () ServerSocket?

Nel mio thread principale ho un ciclo while(listening) che chiama accept() sul mio object ServerSocket, quindi avvia un nuovo thread client e lo aggiunge a una Collection quando viene accettato un nuovo client.

Ho anche un thread Admin che voglio usare per emettere comandi, come ‘exit’, che causerà l’arresto di tutti i thread client, lo spegnimento e la chiusura del thread principale, girando l’ascolto su false.

Tuttavia, la chiamata accept() nel while(listening) blocchi del ciclo, e non sembra esserci alcun modo per interromperlo, quindi la condizione while non può essere ricontrollata e il programma non può uscire!

C’è un modo migliore per farlo? O un modo per interrompere il metodo di blocco?

Puoi chiamare close() da un altro thread, e la chiamata accept() SocketException un SocketException .

Imposta il timeout su accept() , quindi la chiamata interromperà il blocco dopo il tempo specificato:

http://docs.oracle.com/javase/7/docs/api/java/net/SocketOptions.html#SO_TIMEOUT

Imposta un timeout sul blocco delle operazioni di Socket :

 ServerSocket.accept(); SocketInputStream.read(); DatagramSocket.receive(); 

L’opzione deve essere impostata prima che l’operazione di blocco entri in vigore. Se il timeout scade e l’operazione continua a bloccare, viene sollevata java.io.InterruptedIOException . In questo caso, lo Socket non è chiuso.

Chiama close() sul ServerSocket un’opzione?

http://java.sun.com/j2se/6/docs/api/java/net/ServerSocket.html#close%28%29

Chiude questo socket. Qualsiasi thread attualmente bloccato in accept () genererà un SocketException.

Puoi semplicemente creare un socket “void” per break serversocket.accept ()

Lato server

 private static final byte END_WAITING = 66; private static final byte CONNECT_REQUEST = 1; while (true) { Socket clientSock = serverSocket.accept(); int code = clientSock.getInputStream().read(); if (code == END_WAITING /*&& clientSock.getInetAddress().getHostAddress().equals(myIp)*/) { // End waiting clients code detected break; } else if (code == CONNECT_REQUEST) { // other action // ... } } 

Metodo per interrompere il ciclo del server

 void acceptClients() { try { Socket s = new Socket(myIp, PORT); s.getOutputStream().write(END_WAITING); s.getOutputStream().flush(); s.close(); } catch (IOException e) { } } 

Il motivo per cui ServerSocket.close() genera un’eccezione è dato dal fatto che si ha un outputstream o un inputstream collegato a quel socket. È ansible evitare questa eccezione in modo sicuro chiudendo prima i flussi di input e output. Quindi prova a chiudere il ServerSocket . Ecco un esempio:

 void closeServer() throws IOException { try { if (outputstream != null) outputstream.close(); if (inputstream != null) inputstream.close(); } catch (IOException e1) { e1.printStackTrace(); } if (!serversock.isClosed()) serversock.close(); } } 

È ansible chiamare questo metodo per chiudere qualsiasi socket da qualsiasi posizione senza ottenere un’eccezione.

Un’altra cosa che puoi provare è più pulita, è controllare un flag nel ciclo accept, e poi quando il tuo thread admin vuole uccidere il thread blocking su accept, impostare il flag (renderlo thread safe) e quindi creare un client socket connessione alla presa di ascolto. L’accettazione smetterà di bloccare e restituirà il nuovo socket. Puoi escogitare qualche semplice cosa di protocollo che dice al thread di ascolto di uscire dal thread in modo pulito. E quindi chiudere la presa sul lato client. Nessuna eccezione, molto più pulito.

Usa serverSocket.setSoTimeout (timeoutInMillis) .

OK, ho lavorato in modo tale da indirizzare la domanda dell’OP più direttamente.

Continua a leggere la risposta breve per un esempio di Thread su come lo utilizzo.

Risposta breve:

 ServerSocket myServer; Socket clientSocket; try { myServer = new ServerSocket(port) myServer.setSoTimeout(2000); //YOU MUST DO THIS ANYTIME TO ASSIGN new ServerSocket() to myServer‼! clientSocket = myServer.accept(); //In this case, after 2 seconds the below interruption will be thrown } catch (java.io.InterruptedIOException e) { /* This is where you handle the timeout. THIS WILL NOT stop the running of your code unless you issue a break; so you can do whatever you need to do here to handle whatever you want to happen when the timeout occurs. */ } 

Esempio di mondo reale:

In questo esempio, ho un ServerSocket in attesa di una connessione all’interno di un thread. Quando chiudo l’app, voglio chiudere il thread (in particolare, il socket) in modo pulito prima di chiudere l’app, quindi uso il .setSoTimeout () sul ServerSocket, quindi utilizzo l’interrupt che viene generato dopo il timeout per controllare e vedere se il genitore sta provando a chiudere il thread. Se è così, allora imposto di chiudere il socket, quindi imposta un flag che indica che il thread è terminato, quindi interrompo il ciclo Thread che restituisce un null.

 package MyServer; import javafx.concurrent.Task; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import javafx.concurrent.Task; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; public class Server { public Server (int port) {this.port = port;} private boolean threadDone = false; private boolean threadInterrupted = false; private boolean threadRunning = false; private ServerSocket myServer = null; private Socket clientSocket = null; private Thread serverThread = null;; private int port; private static final int SO_TIMEOUT = 5000; //5 seconds public void startServer() { if (!threadRunning) { serverThread = new Thread(thisServerTask); serverThread.setDaemon(true); serverThread.start(); } } public void stopServer() { if (threadRunning) { threadInterrupted = true; while (!threadDone) { //We are just waiting for the timeout to exception happen } if (threadDone) {threadRunning = false;} } } public boolean isRunning() {return threadRunning;} private Task thisServerTask = new Task () { @Override public Void call() throws InterruptedException { threadRunning = true; try { myServer = new ServerSocket(port); myServer.setSoTimeout(SO_TIMEOUT); clientSocket = new Socket(); } catch (IOException e) { e.printStackTrace(); } while(true) { try { clientSocket = myServer.accept(); } catch (java.io.InterruptedIOException e) { if (threadInterrupted) { try { clientSocket.close(); } //This is the clean exit I'm after. catch (IOException e1) { e1.printStackTrace(); } threadDone = true; break; } } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } return null; } }; } 

Quindi, nella mia class Controller … (mostrerò solo il codice rilevante, lo massaggerò nel tuo codice secondo necessità)

 public class Controller { Server server = null; private static final int port = 10000; private void stopTheServer() { server.stopServer(); while (server.isRunning() { //We just wait for the server service to stop. } } @FXML private void initialize() { Platform.runLater(()-> { server = new Server(port); server.startServer(); Stage stage = (Stage) serverStatusLabel.getScene().getWindow(); stage.setOnCloseRequest(event->stopTheServer()); }); } } 

Spero che questo aiuti qualcuno in fondo alla strada.