Следите за новинками
в нашем Telegram канале. Жми, чтобы подписаться:)
⊗jvSpSoCls 305 of 322 menu
◀ ▶

Закрытие TCP-сокета в Java

Сокет держит дескриптор ОС и занятый порт на стороне сервера. Если не закрыть Socket и ServerSocket, соединение может висеть, а повторный запуск на том же порту иногда падает с ошибкой «address already in use».

В Java 27 оба класса реализуют AutoCloseable. Блок try-with-resources вызывает close() при выходе из блока, в том числе при исключении. Закрытие Socket обрывает оба направления обмена для этой пары:

import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class Main { public static void main(String[] args) throws Exception { try (ServerSocket server = new ServerSocket(0)) { int port = server.getLocalPort(); Thread worker = new Thread(() -> { try (Socket peer = server.accept()) { BufferedReader input = new BufferedReader( new InputStreamReader(peer.getInputStream()) ); System.out.println(input.readLine()); } catch (Exception e) { throw new RuntimeException(e); } }); worker.start(); try (Socket client = new Socket("localhost", port)) { client.getOutputStream().write("bye\n".getBytes()); } worker.join(); } } }

Закрытие только потока записи на клиенте сообщает серверу, что новых строк не будет: readLine() вернет null, хотя сокет еще открыт для чтения ответа. Так удобно завершать серию строк без немедленного разрыва канала:

import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; public class Main { public static void main(String[] args) throws Exception { try (ServerSocket server = new ServerSocket(0)) { int port = server.getLocalPort(); Thread worker = new Thread(() -> { try (Socket peer = server.accept()) { BufferedReader input = new BufferedReader( new InputStreamReader(peer.getInputStream()) ); BufferedWriter output = new BufferedWriter( new OutputStreamWriter(peer.getOutputStream()) ); while (true) { String line = input.readLine(); if (line == null) { break; } } output.write("closed input"); output.newLine(); output.flush(); } catch (Exception e) { throw new RuntimeException(e); } }); worker.start(); try (Socket client = new Socket("localhost", port)) { BufferedWriter out = new BufferedWriter( new OutputStreamWriter(client.getOutputStream()) ); BufferedReader in = new BufferedReader( new InputStreamReader(client.getInputStream()) ); out.write("last"); out.newLine(); out.flush(); out.close(); System.out.println(in.readLine()); } worker.join(); } } }

После выхода из внешнего try-with-resources ServerSocket перестает слушать порт. Фоновый поток с accept() получит исключение, если слушатель уже закрыт, поэтому в реальных программах цикл accept() завершают флагом или закрытием сокета из главного потока после join() worker.

Клиент отправляет одну строку и закрывает сокет. Сервер должен успеть прочитать строку до получения null.

После output.close() на клиенте сервер шлет "done", клиент читает её до закрытия своего Socket.

← →
↑
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить