Ответ 1
Вы можете вызвать close() из другого потока, а accept() вызовет SocketException.
В моем основном потоке у меня есть цикл while(listening)
, который вызывает accept()
на моем объекте ServerSocket, затем запускает новый клиентский поток и добавляет его в коллекцию при принятии нового клиента.
У меня также есть поток Admin, который я хочу использовать для выдачи команд, таких как "exit", что приведет к отключению всех клиентских потоков, закрытию себя и закрытию основного потока, путем включения ложь.
Однако вызов accept()
в циклах цикла while(listening)
, и, похоже, нет никакого способа прервать его, поэтому условие while не может быть снова проверено, и программа не может выйти!
Есть ли лучший способ сделать это? Или каким-то образом прервать метод блокировки?
Вы можете вызвать close() из другого потока, а accept() вызовет SocketException.
Установите тайм-аут на accept(), тогда вызов будет блокировать блокировку по истечении указанного времени:
http://docs.oracle.com/javase/7/docs/api/java/net/SocketOptions.html#SO_TIMEOUT
Установите тайм-аут блокировки операций сокета: ServerSocket.accept(); SocketInputStream.read(); DatagramSocket.receive();
Параметр должен быть установлен перед вводом в действие блокировки. Если истечет время ожидания и операция будет продолжать блокироваться, возникает java.io.InterruptedIOException. В этом случае сокет не закрывается.
Вызывает функцию close() на сервере ServerSocket?
http://java.sun.com/j2se/6/docs/api/java/net/ServerSocket.html#close%28%29
Закрывает этот сокет. Любой поток, который в настоящий момент заблокирован в accept(), выдает исключение SocketException.
Причина serversocket.close()
вызывает исключение , потому что у вас есть выходной поток или входной поток, подключенный к этому сокету. Вы можете очень хорошо избежать этого исключения безопасно, сначала закрыв входные и выходные потоки. а затем попробуйте закрыть сервер.
Напишите простой метод
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();
}
}
Я могу просто закрыть любой сокет, вызвав этот метод из любого места без каких-либо исключений для обработки.
Вы можете просто создать сокет "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) {
}
}
Еще одна вещь, которую вы можете попробовать, которая является более чистой, - проверить флаг в цикле принятия, а затем, когда ваш поток администратора хочет уничтожить блокировку потока при принятии, установите флаг (сделайте его потокобезопасным), а затем сделайте подключение клиентского сокета к гнезду для прослушивания. Принятие прекратит блокировку и вернет новый сокет. Вы можете проработать какую-то простую информацию о протоколе, сообщающую прослушивающему потоку, чтобы выйти из потока чисто. Затем закройте сокет на стороне клиента. Никаких исключений, гораздо более чистых.