Как я могу прервать метод ServerSocket accept ()?
в моем основном потоке у меня есть while(listening) цикл, который называет accept() на моем объекте ServerSocket, затем запускает новый поток клиента и добавляет его в коллекцию, когда новый клиент принимается.
у меня также есть поток администратора, который я хочу использовать для выдачи команд, таких как "выход", что приведет к закрытию всех клиентских потоков, выключению себя и выключению основного потока, включив прослушивание false.
на
accept() вызов в while(listening) петли блоков, и, похоже, нет никакого способа прервать его, поэтому условие while не может быть проверено снова, и программа не может выйти!есть ли лучший способ сделать это? Или каким-то образом прервать метод блокировки?
8 ответов:
можно назвать
close()из другого потока, иaccept()вызов броситSocketException.
установить тайм-аут на
accept(), то вызов будет тайм-аут блокировки после заданного времени:http://docs.oracle.com/javase/7/docs/api/java/net/SocketOptions.html#SO_TIMEOUT
установить тайм-аут на блокировку
Socketоперации:ServerSocket.accept(); SocketInputStream.read(); DatagramSocket.receive();эта опция должна быть установлена до вступления в силу операции блокировки. Если тайм-аут истекает и операция будет продолжать блокировать,
java.io.InterruptedIOExceptionподнимается. ЭлементSocketis не закрыто в этом случае.
называет
close()наServerSocketвариант?http://java.sun.com/j2se/6/docs/api/java/net/ServerSocket.html#close%28%29
закрывает этот разъем. В настоящее время любой поток блокируется в accept() будет бросать исключение socketexception.
Вы можете просто создать" пустой " сокет для разрыва serversocket.принимаем()
сервер
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 // ... } }метод прерывания цикла сервера
void acceptClients() { try { Socket s = new Socket(myIp, PORT); s.getOutputStream().write(END_WAITING); s.getOutputStream().flush(); s.close(); } catch (IOException e) { } }
причина
ServerSocket.close()выдает исключение это потому что у вас естьoutputstreamилиinputstreamприкреплен к этой розетке. Вы можете безопасно избежать этого исключения, сначала закрыв входные и выходные потоки. Затем попробуйте закрытьServerSocket. Вот пример: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(); } }вы можете вызвать этот метод, чтобы закрыть любой розетки в любом месте без исключения.
еще одна вещь, которую вы можете попробовать, которая чище, - это проверить флаг в цикле accept, а затем, когда ваш поток администратора хочет убить блокировку потока на accept, установите флаг (сделайте его потокобезопасным), а затем установите соединение клиентского сокета с прослушивающим сокетом. Accept прекратит блокировку и вернет новый сокет. Вы можете разработать какую-то простую протокольную вещь, сообщающую слушающему потоку, чтобы выйти из потока чисто. А затем закройте сокет на стороне клиента. Без исключений, много уборщик.
использовать serverSocket.setSoTimeout (timeoutInMillis).
хорошо, я получил это работает таким образом, что решает вопрос ОП более непосредственно.
продолжайте читать мимо короткого ответа для примера потока, как я использую это.
короткий ответ:
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. */ }реальный пример:
в этом примере у меня есть ServerSocket, ожидающий соединения внутри потока. Когда я закрываю приложение, я хочу закрыть поток (более конкретно, сокет) чистым способом, прежде чем я позволю приложению близко, поэтому я использую .setSoTimeout () на ServerSocket затем я использую прерывание, которое выбрасывается после таймаута, чтобы проверить и посмотреть, пытается ли родитель закрыть поток. Если это так, то я устанавливаю закрыть сокет, а затем установить флаг, указывающий, что поток делается, то я вырываюсь из цикла потоков, который возвращает 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<Void> thisServerTask = new Task <Void>() { @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; } }; }тогда, в моем классе контроллера ... (Я буду показывать только соответствующий код, массаж его в свой собственный код по мере необходимости)
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()); }); } }Я надеюсь это помогает кому-то в будущем.
Comments