W3docs

Введение в сетевое взаимодействие 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, без внешней сети.

java— editable, runs on the server

Что следует вынести из этого запуска:

  • Работающие клиент и сервер умещаются в одном коротком файле. В реальных приложениях они разнесены по машинам, но 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.

Практика

Практика
Вы пишете сервис на Java, который обращается к стороннему REST API по HTTPS и нуждается как в синхронных, так и в асинхронных запросах на современном JDK. Какой API является наиболее подходящим выбором?
Вы пишете сервис на Java, который обращается к стороннему REST API по HTTPS и нуждается как в синхронных, так и в асинхронных запросах на современном JDK. Какой API является наиболее подходящим выбором?
Was this page helpful?