Как я могу прервать метод ServerSocket accept ()?
в моем основном потоке у меня есть while(listening)
цикл, который называет accept()
на моем объекте ServerSocket затем запускает новый поток клиента и добавляет его в коллекцию, когда принимается новый клиент.
у меня также есть поток администратора, который я хочу использовать для выдачи команд, таких как "exit", который заставит все клиентские потоки быть закрытыми, закрыть себя и закрыть основной поток, повернув прослушивание 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
поднимается. TheSocket
is в данном случае не закрыто.
называет close()
на ServerSocket
вариант?
http://java.sun.com/j2se/6/docs/api/java/net/ServerSocket.html#close%28%29
закрывает этот разъем. Любой поток, заблокированный в accept (), вызовет исключение SocketException.
вы можете просто создать сокет "void" для break serversocket.accept ()
сервер
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 прекратит блокировку и вернет новый сокет. Вы можете разработать какой-то простой протокол, сообщающий слушающему потоку, чтобы выйти из потока чисто. А затем закройте сокет на стороне клиента. Никаких исключений, много уборщик.
хорошо, я получил это работает таким образом, что решает вопрос OP более непосредственно.
продолжайте читать мимо короткого ответа для примера потока, как я использую это.
короткий ответ:
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());
});
}
}
Я надеюсь это помогает кому-то в будущем.