Как закрыть розетку надлежащим образом?
Это простой TCP-сервер. Как я могу закрыть сокет, когда программа завершена?
Я использую try/finally и пытаюсь закрыть сокет. Но при выходе из программы он не запускает блок finally.
Кто-нибудь может подумать о том, как правильно закрыть розетку?
try {
socket = new ServerSocket(port);
System.out.println("Server is starting on port " + port + " ...");
}catch (IOException e){
System.out.println("Error on socket creation!");
}
Socket connectionSocket = null;
try{
while(true){
try{
connectionSocket = socket.accept();
Thread t = new Thread(new ClientConnection(connectionSocket));
t.start();
}catch (IOException e) {
System.out.println("Error on accept socket!");
}
}
}finally{
this.socket.close();
System.out.println("The server is shut down!");
}
Ответы
Ответ 1
После создания ServerSocket вы можете добавить ShutdownHook, чтобы закрыть его при завершении JVM, примерно так:
Runtime.getRuntime().addShutdownHook(new Thread(){public void run(){
try {
socket.close();
System.out.println("The server is shut down!");
} catch (IOException e) { /* failed */ }
}});
Вызов ServerSocket # закрыть завершает блокировку ServerSocket.accept, вызывая его исключение SocketException. Однако обратите внимание, что ваша текущая обработка IOException в цикле while означает, что вы снова войдете в цикл while, чтобы попытаться принять на закрытом сокете. JVM все равно будет завершен, но он немного неопрятен.
Крюки выключения не запускаются, если вы завершаете консольное приложение в Eclipse (по крайней мере на Windows). Но они запускаются, если вы CTRL-C Java в обычной консоли. Для их запуска вам необходимо, чтобы JVM прерывался нормально, например. SIGINT или SIGTERM, а не SIGKILL (kill -9).
Простая программа, которую вы можете выполнить в Eclipse или консоли, продемонстрирует это.
public class Test implements Runnable {
public static void main(String[] args) throws InterruptedException {
final Test test = new Test();
Runtime.getRuntime().addShutdownHook(new Thread(){public void run(){
test.shutdown();
}});
Thread t = new Thread(test);
t.start();
}
public void run() {
synchronized(this) {
try {
System.err.println("running");
wait();
} catch (InterruptedException e) {}
}
}
public void shutdown() {
System.err.println("shutdown");
}
}
Ответ 2
Нет необходимости в вашем конкретном случае, операционная система закроет все сокеты TCP для вас, когда программа выйдет.
Ответ 3
От javadoc:
Время выполнения Java автоматически закрывает входные и выходные потоки, клиентский сокет и серверный сокет, поскольку они были созданный в инструкции try-with-resources.
Кроме
Метод finalize()
вызывается виртуальной машиной Java (JVM
) перед выходом программы, чтобы дать программе возможность очистить и релиз ресурсов. Многопоточные программы должны закрывать все файлы и Сокеты, которые они используют перед выходом, так что они не сталкиваются с ресурсом голодание. Вызов метода server.close()
в методе finalize()
закрывается соединение Socket, используемое каждым потоком в этой программе.
protected void finalize(){
//Objects created in run method are finalized when
//program terminates and thread exits
try{
server.close();
} catch (IOException e) {
System.out.println("Could not close socket");
System.exit(-1);
}
}
Ответ 4
Howcome, наконец, не запущен? Вероятно, while (true) следует заменить чем-то вроде
while (!shutdownRequested)
в качестве альтернативы вы можете создать крюк отключения, который обрабатывает сокет close
Ответ 5
Ну, как вы "выходите" из программы? finally
будет выполняться, если будет выбрано исключение или если блок try завершит свое выполнение "обычным" способом, но я думаю, что это может быть "сложно" из-за вашего while(true)
.
Чтобы закрыть сокет, вы должны использовать socket.close()
, и я бы рекомендовал вам не полагаться на функцию destroy.
Ответ 6
Класс ServerSocker
является AutoCloseable
. Поэтому правильный способ использовать ServerSocket
экземпляра находится с try
-са-ресурсы блоком, так что гнездо надежно закрыто, если исключение. Не используйте блок try
... finally
: он будет работать неправильно для некоторых крайних случаев (случаев, которые требуют исключенного исключения). Не используйте shutdown-hook: сокет не должен быть глобальным ресурсом, и такой подход будет подвержен гоночным опасностям. try
-with-resources является рекомендуемым способом правильного закрытия всех ресурсов ввода-вывода, таких как сокет.
try (ServerSocket socket = new ServerSocket(...)) {
... // use the socket
} catch (IOException e) {
... // exception handling code
}