Введение в сетевое взаимодействие Java
Обзор сетевых API Java в java.net и java.net.http для подключения к удалённым сервисам.
Сетевое взаимодействие — это способ, которым программа на Java общается с другой программой: в соседней комнате или на другом конце света. JDK поставляется с полным стеком для этого в двух пакетах: давно существующий java.net (URL-адреса, сокеты, адреса) и современный java.net.http (HttpClient, введённый в Java 11). Эта часть книги знакомит со стеком — от высокоуровневых удобств до низкоуровневых сокетов.
Уровни — от высокого к низкому
Сетевые API Java образуют лестницу. Выбирайте самую высокую ступень, которая решает задачу:
| Ступень | API | Использование |
|---|---|---|
| Высшая | HttpClient (java.net.http) | Современный HTTP/HTTPS: REST-вызовы, загрузки, async |
URL / URLConnection / HttpURLConnection | Устаревший HTTP и другие URL-протоколы | |
Socket / ServerSocket | Собственные TCP-протоколы, свои клиент/сервер | |
| Низшая | DatagramSocket | Бессоединительные UDP-сообщения |
| Вспомогательная | InetAddress | Разрешение и представление IP-адресов |
Практическое правило: если вы обращаетесь к HTTP API, используйте HttpClient. Переходите к сокетам только тогда, когда работаете с протоколом, отличным от HTTP, или строите собственный сервер.
TCP против UDP
Почти всё основано на двух транспортных протоколах:
- TCP (
Socket,ServerSocket) — это соединение: надёжное, упорядоченное, потоковое. Байты, которые вы записываете, доходят целыми и по порядку, иначе вы получаете ошибку. HTTP, базы данных и большинство прикладных протоколов работают поверх TCP. - UDP (
DatagramSocket) — это бессоединительный режим: вы отправляете независимые пакеты («датаграммы») без рукопожатия, без упорядочения и без гарантий доставки. Он жертвует надёжностью ради низкой задержки — используется для DNS, видеостриминга и игр.
Клиент против сервера
Клиент инициирует соединение с известным адресом и портом. Сервер привязывается к порту и ждёт принятия входящих соединений. Один и тот же класс Socket представляет живое соединение с обеих сторон; асимметрия лишь в том, кто начинает разговор. В последующих главах строятся обе стороны.
Блокировка по умолчанию
Классические API java.net являются блокирующими: socket.getInputStream().read() останавливает вызывающий поток до прихода данных, а serverSocket.accept() — до подключения клиента. Это просто в понимании, но означает один поток на соединение. (Каналы java.nio и виртуальные потоки решают проблему масштабирования; эта часть остаётся на блокирующих API, которые являются правильной отправной точкой.)
Рабочий пример: весь стек в одном файле
Чтобы сделать части конкретными, эта программа запускает крошечный HTTP-сервер на интерфейсе loopback, а затем обращается к нему с помощью современного HttpClient — полный цикл клиент/сервер в одной JVM, без внешней сети.
Что следует вынести из этого запуска:
- Работающие клиент и сервер умещаются в одном коротком файле. В реальных приложениях они разнесены по машинам, но API идентичен —
HttpServerпринял соединение, аHttpClientоткрыл его, встретившись по TCP на интерфейсе loopback (127.0.0.1). Это форма каждой сетевой программы: одна сторона ждёт, другая вызывает. - Привязка к порту 0 позволила ОС выбрать свободный порт, который
server.getAddress().getPort()вернул обратно. Жёсткое указание порта рискует получить «адрес уже используется»; порт 0 — стандартный приём для тестов и демонстраций, которым нужен любой порт. - Клиент никогда не обращался к сокету напрямую.
HttpClientобработал соединение, строку HTTP-запроса, заголовки и разбор ответа — в этом и есть ценность подъёма на верхнюю ступень лестницы. В главах про сокеты будет показано, что он скрывал. - Ответ содержал структурированные метаданные:
statusCode()(200),body()иversion(). HTTP-ответы — это больше, чем текст; клиент смоделировал их как типизированный объектHttpResponse, чтобы вы читали поля, а не разбирали поток. server.stop(0)освободил порт. Сетевые ресурсы — сокеты, серверные порты, соединения — это редкие дескрипторы ОС; каждая глава этой части закрывает их явно (или через try-with-resources), чтобы они не утекали.
Что охватывает остальная часть
Следующие главы спускаются вниз по лестнице:
- Класс
URLиURLConnection/HttpURLConnection— разбор URL-адресов и устаревший API соединений. - Современный
HttpClientподробно — синхронные и асинхронные HTTP/2-запросы. - Низкоуровневый TCP с
SocketиServerSocket— создание собственных клиента и сервера. - Бессоединительный UDP с
DatagramSocket. - Разрешение адресов с
InetAddress.
Следующая глава начинается с самого знакомого сетевого объекта: URL.