Como posso interromper um método ServerSocket accept ()?

No meu thread principal, tenho um loop while(listening) que chama accept() no meu object ServerSocket, em seguida, inicia um novo thread de cliente e o adiciona a uma Collection quando um novo cliente é aceito.

Eu também tenho um thread de administração que eu quero usar para emitir comandos, como ‘exit’, que fará com que todos os threads do cliente sejam desligados, desligue-se e desligue o thread principal, transformando o escutando em falso.

No entanto, a chamada accept() no while(listening) bloqueia, e não parece haver nenhuma maneira de interrompê-la, então a condição while não pode ser verificada novamente e o programa não pode sair!

Existe uma maneira melhor de fazer isso? Ou alguma maneira de interromper o método de bloqueio?

Você pode chamar close() de outro thread, e a chamada accept() lançará um SocketException .

Definir timeout em accept() , então a chamada irá tempo limite do bloqueio após o tempo especificado:

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

Definir um tempo limite no bloqueio de operações de Socket :

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

A opção deve ser definida antes de inserir uma operação de bloqueio para entrar em vigor. Se o tempo limite expirar e a operação continuar bloqueando, java.io.InterruptedIOException será gerado. O Socket não está fechado neste maiúsculas e minúsculas.

Está chamando close() no ServerSocket uma opção?

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

Fecha este soquete. Qualquer thread atualmente bloqueado em accept () lançará um SocketException.

Você pode apenas criar um socket “void” para o serverockets.accept ()

Lado do servidor

 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 // ... } } 

Método para o ciclo do servidor de quebra

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

A razão pela qual ServerSocket.close() lança uma exceção é porque você tem um outputstream ou um inputstream anexado a esse soquete. Você pode evitar essa exceção com segurança, primeiro fechando os streams de input e saída. Em seguida, tente fechar o ServerSocket . Aqui está um exemplo:

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

Você pode chamar esse método para fechar qualquer soquete de qualquer lugar sem obter uma exceção.

Outra coisa que você pode tentar, que é mais limpo, é verificar um sinalizador no loop de aceitação e, em seguida, quando seu segmento admin quer matar o bloqueio de segmento no aceitar, defina o sinalizador (torná-lo thread seguro) e faça um soquete de cliente conexão ao soquete de escuta. A aceitação irá parar de bloquear e devolver o novo socket. Você pode elaborar alguma coisa simples de protocolo dizendo ao thread de atendimento para sair do thread de forma limpa. E feche o soquete no lado do cliente. Sem exceções, muito mais limpo.

Use serverSocket.setSoTimeout (timeoutInMillis) .

OK, eu tenho isso funcionando de uma forma que aborda a questão do OP mais diretamente.

Continue lendo após a resposta curta para um exemplo de Thread de como eu uso isso.

Resposta curta:

 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. */ } 

Exemplo do mundo real:

Neste exemplo, eu tenho um ServerSocket esperando por uma conexão dentro de um Thread. Quando eu fechar o aplicativo, eu quero desligar o segmento (mais especificamente, o soquete) de uma maneira limpa antes de deixar o aplicativo fechar, então eu uso o .setSoTimeout () no ServerSocket, então eu uso a interrupção que é lançada após o tempo limite para verificar e ver se o pai está tentando desligar o segmento. Se assim for, então eu defino fechar o soquete, em seguida, defina um sinalizador indicando que o segmento é feito, então eu saio do loop Threads, que retorna um nulo.

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

Então, na minha class Controller … (mostrarei apenas o código relevante, massageie-o em seu próprio código, conforme necessário)

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

Espero que isso ajude alguém na estrada.