Раздел 12. Работа с файлами, I/O и сетью (NIO.2)
Глава 4. Работа с сетью (Socket, HTTP, HttpClient)
Основы сетевого взаимодействия: IP-адреса, порты, протоколы
Сетевое взаимодействие — это фундамент, на котором строится любое распределённое приложение. Будь то веб-сервис, микросервисная архитектура, потоковое видео или онлайн-игра, всё сводится к передаче данных между двумя точками через сеть.
В Java сетевая функциональность реализована в пакетах
IP-адрес: логический адрес в сети
IP-адрес (Internet Protocol address) — это числовой идентификатор, присваиваемый каждому устройству, подключённому к сети, работающей по протоколу IP.
IP-адрес выполняет две функции: идентификация хоста (устройства) и маршрутизация — определение пути, по которому данные должны добраться до получателя.
IPv4
IPv4 (Internet Protocol version 4) — четвёртая версия протокола, введённая в 1981 году. Адрес IPv4 представляет собой 32-битное число, разделённое на четыре октета (группы по 8 бит), записываемых в десятичной нотации через точку:
32 бита дают теоретический лимит в 4 294 967 296 уникальных адресов. На практике адресное пространство исчерпано из-за неэффективного распределения в ранние годы интернета и роста числа устройств. Чтобы продлить жизнь IPv4, были введены технологии NAT (Network Address Translation — преобразование сетевых адресов), позволяющие множеству устройств в локальной сети использовать один внешний IP-адрес, и CIDR (Classless Inter-Domain Routing — бесклассовая междоменная маршрутизация), которая позволяет гибко делить адресное пространство на подсети произвольного размера.
В Java адрес IPv4 представляется классом
Метод
IPv6
IPv6 (Internet Protocol version 6) — шестая версия, разработанная как преемник IPv4. Адрес IPv6 — это 128-битное число, записываемое в шестнадцатеричной нотации через двоеточия:
128 бит дают 3.4 × 10^38 адресов — количество, достаточное для присвоения IP каждому атому на поверхности Земли. IPv6 устраняет необходимость в NAT, упрощает маршрутизацию за счёт фиксированного размера заголовка (в отличие от переменного в IPv4) и встроено поддерживает IPsec — протокол шифрования и аутентификации на сетевом уровне.
В Java IPv6 представлен классом
Специальные адреса
Приватные адреса (RFC 1918):
Multicast:
Broadcast (широковещательный адрес): в IPv4
Порт: точка входа в приложение
Если IP-адрес идентифицирует устройство в сети, то порт (port) идентифицирует конкретное приложение или процесс на этом устройстве. Порт — это 16-битное число от 0 до 65535, которое добавляется к IP-адресу, образуя полный адрес конечной точки связи.
Диапазоны портов
Well-known ports (0–1023): зарезервированы IANA для стандартных протоколов. Например: 22 — SSH, 80 — HTTP, 443 — HTTPS, 53 — DNS. На Unix-подобных системах привязка к этим портам требует прав суперпользователя (root).
Registered ports (1024–49151): зарегистрированы IANA для конкретных сервисов, но не требуют root. Например: 3306 — MySQL, 5432 — PostgreSQL, 8080 — альтернативный HTTP.
Dynamic / Private / Ephemeral ports (49152–65535): временные порты, которые ОС назначает клиентским приложениям при исходящих соединениях. Когда ваш браузер открывает соединение с сервером на порту 443, ОС выбирает свободный эфемерный порт из этого диапазона для локальной стороны соединения.
Передача
#Java #для_новичков #beginner #IO #NIO #Ip #Port #TCP #UDP
Глава 4. Работа с сетью (Socket, HTTP, HttpClient)
Основы сетевого взаимодействия: IP-адреса, порты, протоколы
Сетевое взаимодействие — это фундамент, на котором строится любое распределённое приложение. Будь то веб-сервис, микросервисная архитектура, потоковое видео или онлайн-игра, всё сводится к передаче данных между двумя точками через сеть.
В Java сетевая функциональность реализована в пакетах
java.net и java.nio.channels, а понимание нижележащих протоколов — обязательное требование для разработчика, который проектирует производительные и надёжные системы.Протокол — это формальный набор правил, определяющий формат, порядок и обработку данных при их передаче между устройствами. Протоколы работают на разных уровнях абстракции: от физического уровня (электрические сигналы в кабеле) до прикладного (HTTP, gRPC). В Java-разработке нас интересуют прежде всего транспортный и прикладной уровни модели TCP/IP.
TCP/IP — это стек протоколов, лежащий в основе интернета. Вместо семиуровневой модели OSI в инженерной практике используется упрощённая четырёхуровневая модель: канальный уровень (Ethernet, Wi-Fi), сетевой (IP), транспортный (TCP, UDP) и прикладной (HTTP, DNS, SSH).
IP-адрес: логический адрес в сети
IP-адрес (Internet Protocol address) — это числовой идентификатор, присваиваемый каждому устройству, подключённому к сети, работающей по протоколу IP.
IP-адрес выполняет две функции: идентификация хоста (устройства) и маршрутизация — определение пути, по которому данные должны добраться до получателя.
IPv4
IPv4 (Internet Protocol version 4) — четвёртая версия протокола, введённая в 1981 году. Адрес IPv4 представляет собой 32-битное число, разделённое на четыре октета (группы по 8 бит), записываемых в десятичной нотации через точку:
192.168.1.1.32 бита дают теоретический лимит в 4 294 967 296 уникальных адресов. На практике адресное пространство исчерпано из-за неэффективного распределения в ранние годы интернета и роста числа устройств. Чтобы продлить жизнь IPv4, были введены технологии NAT (Network Address Translation — преобразование сетевых адресов), позволяющие множеству устройств в локальной сети использовать один внешний IP-адрес, и CIDR (Classless Inter-Domain Routing — бесклассовая междоменная маршрутизация), которая позволяет гибко делить адресное пространство на подсети произвольного размера.
В Java адрес IPv4 представляется классом
Inet4Address, наследником InetAddress.import java.net.InetAddress;
import java.net.UnknownHostException;
public class IpExample {
public static void main(String[] args) throws UnknownHostException {
// Разрешение доменного имени в IP-адрес через DNS
InetAddress address = InetAddress.getByName("www.example.com");
System.out.println(address.getHostAddress()); // 93.184.216.34
System.out.println(address instanceof java.net.Inet4Address); // true
}
}
Метод
getByName() выполняет DNS-резолюцию (Domain Name System resolution — преобразование доменного имени в IP-адрес). Это блокирующий вызов: поток приостанавливается до получения ответа от DNS-сервера. В современном Java для неблокирующей работы используется java.net.InetAddress в сочетании с CompletableFuture или HttpClient.IPv6
IPv6 (Internet Protocol version 6) — шестая версия, разработанная как преемник IPv4. Адрес IPv6 — это 128-битное число, записываемое в шестнадцатеричной нотации через двоеточия:
2001:0db8:85a3:0000:0000:8a2e:0370:7334. Для краткости ведущие нули в группе можно опускать, а одну последовательность из нулевых групп — заменять двойным двоеточием: 2001:db8:85a3::8a2e:370:7334.128 бит дают 3.4 × 10^38 адресов — количество, достаточное для присвоения IP каждому атому на поверхности Земли. IPv6 устраняет необходимость в NAT, упрощает маршрутизацию за счёт фиксированного размера заголовка (в отличие от переменного в IPv4) и встроено поддерживает IPsec — протокол шифрования и аутентификации на сетевом уровне.
В Java IPv6 представлен классом
Inet6Address. JVM автоматически предпочитает IPv6, если хост поддерживает оба стека (свойство java.net.preferIPv4Stack и java.net.preferIPv6Addresses управляют этим поведением).InetAddress ipv6 = InetAddress.getByName("::1"); // loopback в IPv6
System.out.println(ipv6 instanceof java.net.Inet6Address); // trueLoopback (петлевой адрес) — это специальный адрес, который всегда указывает на текущий хост. В IPv4 это 127.0.0.1, в IPv6 — ::1. Пакеты, отправленные на loopback, не выходят за пределы сетевого стека ОС и не попадают в физический интерфейс.
Специальные адреса
Приватные адреса (RFC 1918):
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 — используются только внутри локальных сетей, не маршрутизируются в интернете.Multicast:
224.0.0.0/4 в IPv4, ff00::/8 в IPv6 — адреса для групповой рассылки, когда один пакет доставляется множеству получателей.Broadcast (широковещательный адрес): в IPv4
255.255.255.255 или адрес подсети с единицами в хостовой части — отправка пакета всем устройствам в сегменте сети. В IPv6 broadcast отсутствует, его заменяет multicast.Маршрутизация (routing) — это процесс выбора пути для сетевого пакета от источника к получателю через промежуточные узлы (роутеры). Каждый роутер принимает решение на основе таблицы маршрутизации и заголовка IP-пакета.
Порт: точка входа в приложение
Если IP-адрес идентифицирует устройство в сети, то порт (port) идентифицирует конкретное приложение или процесс на этом устройстве. Порт — это 16-битное число от 0 до 65535, которое добавляется к IP-адресу, образуя полный адрес конечной точки связи.
Сокет (socket) — это абстракция, представляющая одну конечную точку сетевого соединения. В TCP сокет однозначно определяется четвёркой: IP-источника, порт-источника, IP-назначения, порт-назначения. В Java сокет представлен классами java.net.Socket (клиент) и java.net.ServerSocket (сервер).
Диапазоны портов
Well-known ports (0–1023): зарезервированы IANA для стандартных протоколов. Например: 22 — SSH, 80 — HTTP, 443 — HTTPS, 53 — DNS. На Unix-подобных системах привязка к этим портам требует прав суперпользователя (root).
Registered ports (1024–49151): зарегистрированы IANA для конкретных сервисов, но не требуют root. Например: 3306 — MySQL, 5432 — PostgreSQL, 8080 — альтернативный HTTP.
Dynamic / Private / Ephemeral ports (49152–65535): временные порты, которые ОС назначает клиентским приложениям при исходящих соединениях. Когда ваш браузер открывает соединение с сервером на порту 443, ОС выбирает свободный эфемерный порт из этого диапазона для локальной стороны соединения.
Эфемерный порт (ephemeral port) — это временный порт, автоматически выделяемый стеком TCP/IP операционной системы для исходящего соединения. После закрытия соединения порт переходит в состояние TIME_WAIT и освобождается через несколько минут.
import java.net.InetSocketAddress;
// InetSocketAddress объединяет IP-адрес и порт
InetSocketAddress serverAddr = new InetSocketAddress("192.168.1.100", 8080);
InetSocketAddress localAddr = new InetSocketAddress("0.0.0.0", 0); // порт 0 = эфемерный
Передача
0 в качестве порта при создании Socket или ServerSocket означает "выбрать любой свободный эфемерный порт". После привязки реальный порт можно узнать через socket.getLocalPort().#Java #для_новичков #beginner #IO #NIO #Ip #Port #TCP #UDP
👍4
TCP: Transmission Control Protocol
TCP (Transmission Control Protocol — протокол управления передачей) — это основной транспортный протокол интернета, обеспечивающий надёжную, упорядоченную и проверенную доставку потока байтов между приложениями. TCP работает поверх IP и добавляет к нему механизмы контроля, которых у IP нет.
Трёхэтапное рукопожатие (Three-way Handshake)
Перед передачей данных TCP устанавливает соединение через процедуру, состоящую из трёх сообщений:
SYN (Synchronize — синхронизация): клиент отправляет серверу сегмент с флагом SYN и случайным начальным номером последовательности (ISN, Initial Sequence Number). ISN выбирается случайно для защиты от атак типа TCP sequence prediction.
SYN-ACK (Synchronize-Acknowledge): сервер получает SYN, выделяет ресурсы для соединения (создаёт запись в таблице соединений, буферы приёма и передачи), генерирует свой ISN и отправляет ответ с флагами SYN и ACK. Поле ACK содержит номер последовательности клиента плюс один, подтверждая получение SYN.
ACK (Acknowledge): клиент получает SYN-ACK, подтверждает получение отправкой ACK (номер последовательности сервера плюс один), и переходит в состояние ESTABLISHED. Сервер, получив ACK, также переходит в ESTABLISHED. Соединение установлено, и начинается передача данных.
Гарантия доставки
TCP гарантирует доставку данных через механизм подтверждений (acknowledgments, ACK). Каждый отправленный сегмент должен быть подтверждён получателем. Если отправитель не получает ACK в течение RTO (Retransmission Timeout — таймаута повторной передачи), он повторно отправляет сегмент. RTO вычисляется динамически на основе RTT (Round-Trip Time — времени оборота пакета до получателя и обратно).
Кроме того, TCP использует контрольную сумму (checksum) — 16-битное значение, вычисляемое над заголовком и данными сегмента. Если получатель вычисляет checksum, которая не совпадает с переданной, сегмент отбрасывается, и отправитель, не получив ACK, повторит передачу.
Упорядоченность
IP не гарантирует порядок доставки пакетов: они могут идти разными маршрутами и приходить вперемешку. TCP решает эту проблему через номера последовательности (sequence numbers). Каждый байт в потоке имеет порядковый номер. Получатель собирает сегменты в правильном порядке по этим номерам и передаёт упорядоченный поток приложению. Если сегмент приходит с разрывом (например, получены байты 1–1000 и 2001–3000, но 1001–2000 потеряны), получатель буферизует пришедшие данные и ждёт недостающий сегмент, не передавая приложению неполный поток.
Управление потоком (Flow Control)
Управление потоком — это механизм, предотвращающий переполнение буфера получателя. В заголовке TCP есть поле Window Size (размер окна) — количество байтов, которое получатель готов принять. Отправитель не отправляет больше данных, чем позволяет окно. Если приложение-получатель медленно читает данные из сокета, окно уменьшается до нуля (Zero Window), и отправитель приостанавливает передачу до обновления окна.
Контроль перегрузки (Congestion Control)
Контроль перегрузки — это механизм, предотвращающий перегрузку сети. В отличие от управления потоком, которое защищает получателя, контроль перегрузки защищает сеть. TCP медленно увеличивает скорость передачи (slow start), экспоненциально наращивая количество сегментов, пока не обнаружит потерю (по таймауту или дублированным ACK). При потере скорость резко снижается. Современные алгоритмы: CUBIC (по умолчанию в Linux), BBR (разработан Google, учитывает пропускную способность и RTT).
Завершение соединения: четырёхэтапное прощание
Закрытие TCP соединения требует четырёх сообщений:
FIN: инициатор (например, клиент) отправляет FIN, сообщая, что он больше не будет отправлять данные.
ACK: получатель подтверждает FIN.
FIN: получатель, завершив передачу своих данных, отправляет свой FIN.
ACK: инициатор подтверждает FIN.
После этого соединение переходит в состояние TIME_WAIT на стороне инициатора закрытия. Это состояние длится обычно 2 × MSL (Maximum Segment Lifetime, 60–120 секунд) и необходимо для надёжного закрытия: если последний ACK потеряется, получатель повторит FIN, и инициатор должен быть готов отправить ACK повторно. TIME_WAIT также предотвращает попадание задержанных сегментов из старого соединения в новое с теми же параметрами.
UDP: User Datagram Protocol
UDP (User Datagram Protocol — протокол пользовательских датаграмм) — это минималистичный транспортный протокол, работающий поверх IP. В отличие от TCP, UDP не устанавливает соединения, не гарантирует доставку, не обеспечивает упорядоченность и не контролирует перегрузку.
Структура и принцип работы
UDP-заголовок занимает всего 8 байт (против 20+ байт у TCP) и содержит четыре поля: порт источника, порт назначения, длина датаграммы и контрольную сумму. После формирования датаграммы ОС немедленно отправляет её в сеть. Нет рукопожатия, нет ожидания подтверждений, нет повторных передач.
Потеря пакетов
UDP не обнаруживает потерю пакетов на транспортном уровне. Если датаграмма потерялась в сети, получатель об этом не узнает, а отправитель не повторит передачу. Это делает UDP непригодным для передачи файлов или текстовых данных без дополнительной логики поверх протокола. Однако именно отсутствие гарантий даёт UDP преимущество в скорости и задержке (latency).
Преимущества UDP
Низкая задержка: отсутствие рукопожатия и ожидания ACK означает, что первый байт данных уходит в сеть немедленно.
Отсутствие head-of-line blocking: в TCP, если один сегмент потерян, все последующие сегменты задерживаются в буфере до получения недостающего. В UDP каждая датаграмма независима.
Multicast и broadcast: UDP естественно поддерживает отправку одной датаграммы множеству получателей, что невозможно в TCP (TCP — исключительно one-to-one).
Меньший оверхед: 8-байтный заголовок против 20+ байт у TCP, меньше CPU-нагрузки на обработку.
Когда что использовать
Выбор между TCP и UDP определяется требованиями приложения к надёжности, задержке и порядку данных.
#Java #для_новичков #beginner #IO #NIO #Ip #Port #TCP #UDP
TCP (Transmission Control Protocol — протокол управления передачей) — это основной транспортный протокол интернета, обеспечивающий надёжную, упорядоченную и проверенную доставку потока байтов между приложениями. TCP работает поверх IP и добавляет к нему механизмы контроля, которых у IP нет.
Трёхэтапное рукопожатие (Three-way Handshake)
Перед передачей данных TCP устанавливает соединение через процедуру, состоящую из трёх сообщений:
SYN (Synchronize — синхронизация): клиент отправляет серверу сегмент с флагом SYN и случайным начальным номером последовательности (ISN, Initial Sequence Number). ISN выбирается случайно для защиты от атак типа TCP sequence prediction.
SYN-ACK (Synchronize-Acknowledge): сервер получает SYN, выделяет ресурсы для соединения (создаёт запись в таблице соединений, буферы приёма и передачи), генерирует свой ISN и отправляет ответ с флагами SYN и ACK. Поле ACK содержит номер последовательности клиента плюс один, подтверждая получение SYN.
ACK (Acknowledge): клиент получает SYN-ACK, подтверждает получение отправкой ACK (номер последовательности сервера плюс один), и переходит в состояние ESTABLISHED. Сервер, получив ACK, также переходит в ESTABLISHED. Соединение установлено, и начинается передача данных.
Флаг в контексте TCP — это битовое поле в заголовке сегмента, управляющее поведением протокола. Флаги: SYN (начало соединения), ACK (подтверждение), FIN (завершение), RST (сброс), PSH (немедленная передача данных приложению), URG (срочные данные).
// Псевдокод трёхэтапного рукопожатия на уровне сокетов Java
// На самом деле это происходит внутри ядра ОС, Java лишь инициирует
// Клиент
Socket clientSocket = new Socket();
clientSocket.connect(serverAddress); // Внутри ядра: отправка SYN -> получение SYN-ACK -> отправка ACK
// Сервер
ServerSocket serverSocket = new ServerSocket(8080);
Socket acceptedSocket = serverSocket.accept(); // Внутри ядра: получение SYN -> отправка SYN-ACK -> получение ACK
Гарантия доставки
TCP гарантирует доставку данных через механизм подтверждений (acknowledgments, ACK). Каждый отправленный сегмент должен быть подтверждён получателем. Если отправитель не получает ACK в течение RTO (Retransmission Timeout — таймаута повторной передачи), он повторно отправляет сегмент. RTO вычисляется динамически на основе RTT (Round-Trip Time — времени оборота пакета до получателя и обратно).
Кроме того, TCP использует контрольную сумму (checksum) — 16-битное значение, вычисляемое над заголовком и данными сегмента. Если получатель вычисляет checksum, которая не совпадает с переданной, сегмент отбрасывается, и отправитель, не получив ACK, повторит передачу.
Упорядоченность
IP не гарантирует порядок доставки пакетов: они могут идти разными маршрутами и приходить вперемешку. TCP решает эту проблему через номера последовательности (sequence numbers). Каждый байт в потоке имеет порядковый номер. Получатель собирает сегменты в правильном порядке по этим номерам и передаёт упорядоченный поток приложению. Если сегмент приходит с разрывом (например, получены байты 1–1000 и 2001–3000, но 1001–2000 потеряны), получатель буферизует пришедшие данные и ждёт недостающий сегмент, не передавая приложению неполный поток.
Управление потоком (Flow Control)
Управление потоком — это механизм, предотвращающий переполнение буфера получателя. В заголовке TCP есть поле Window Size (размер окна) — количество байтов, которое получатель готов принять. Отправитель не отправляет больше данных, чем позволяет окно. Если приложение-получатель медленно читает данные из сокета, окно уменьшается до нуля (Zero Window), и отправитель приостанавливает передачу до обновления окна.
Контроль перегрузки (Congestion Control)
Контроль перегрузки — это механизм, предотвращающий перегрузку сети. В отличие от управления потоком, которое защищает получателя, контроль перегрузки защищает сеть. TCP медленно увеличивает скорость передачи (slow start), экспоненциально наращивая количество сегментов, пока не обнаружит потерю (по таймауту или дублированным ACK). При потере скорость резко снижается. Современные алгоритмы: CUBIC (по умолчанию в Linux), BBR (разработан Google, учитывает пропускную способность и RTT).
Завершение соединения: четырёхэтапное прощание
Закрытие TCP соединения требует четырёх сообщений:
FIN: инициатор (например, клиент) отправляет FIN, сообщая, что он больше не будет отправлять данные.
ACK: получатель подтверждает FIN.
FIN: получатель, завершив передачу своих данных, отправляет свой FIN.
ACK: инициатор подтверждает FIN.
После этого соединение переходит в состояние TIME_WAIT на стороне инициатора закрытия. Это состояние длится обычно 2 × MSL (Maximum Segment Lifetime, 60–120 секунд) и необходимо для надёжного закрытия: если последний ACK потеряется, получатель повторит FIN, и инициатор должен быть готов отправить ACK повторно. TIME_WAIT также предотвращает попадание задержанных сегментов из старого соединения в новое с теми же параметрами.
UDP: User Datagram Protocol
UDP (User Datagram Protocol — протокол пользовательских датаграмм) — это минималистичный транспортный протокол, работающий поверх IP. В отличие от TCP, UDP не устанавливает соединения, не гарантирует доставку, не обеспечивает упорядоченность и не контролирует перегрузку.
Структура и принцип работы
UDP-заголовок занимает всего 8 байт (против 20+ байт у TCP) и содержит четыре поля: порт источника, порт назначения, длина датаграммы и контрольную сумму. После формирования датаграммы ОС немедленно отправляет её в сеть. Нет рукопожатия, нет ожидания подтверждений, нет повторных передач.
Датаграмма (datagram) — это самостоятельная единица данных, передаваемая через сеть без установления соединения. Каждая датаграмма независима: она может идти своим маршрутом, прийти в другом порядке или не прийти вовсе.
// UDP-сервер: приём датаграмм
DatagramSocket serverSocket = new DatagramSocket(9876);
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
serverSocket.receive(packet); // Блокирующее ожидание датаграммы
String received = new String(packet.getData(), 0, packet.getLength());
// UDP-клиент: отправка датаграммы
DatagramSocket clientSocket = new DatagramSocket(); // эфемерный порт
byte[] sendData = "Hello, UDP".getBytes();
DatagramPacket sendPacket = new DatagramPacket(
sendData, sendData.length,
InetAddress.getByName("localhost"), 9876
);
clientSocket.send(sendPacket); // Отправка без установления соединения
Потеря пакетов
UDP не обнаруживает потерю пакетов на транспортном уровне. Если датаграмма потерялась в сети, получатель об этом не узнает, а отправитель не повторит передачу. Это делает UDP непригодным для передачи файлов или текстовых данных без дополнительной логики поверх протокола. Однако именно отсутствие гарантий даёт UDP преимущество в скорости и задержке (latency).
Задержка (latency) — это время, которое требуется пакету для прохождения от отправителя к получателю. В TCP задержка включает время рукопожатия, ожидание ACK, повторные передачи. В UDP задержка минимальна: данные отправляются сразу.
Преимущества UDP
Низкая задержка: отсутствие рукопожатия и ожидания ACK означает, что первый байт данных уходит в сеть немедленно.
Отсутствие head-of-line blocking: в TCP, если один сегмент потерян, все последующие сегменты задерживаются в буфере до получения недостающего. В UDP каждая датаграмма независима.
Multicast и broadcast: UDP естественно поддерживает отправку одной датаграммы множеству получателей, что невозможно в TCP (TCP — исключительно one-to-one).
Меньший оверхед: 8-байтный заголовок против 20+ байт у TCP, меньше CPU-нагрузки на обработку.
Когда что использовать
Выбор между TCP и UDP определяется требованиями приложения к надёжности, задержке и порядку данных.
#Java #для_новичков #beginner #IO #NIO #Ip #Port #TCP #UDP
👍4
HTTP и HTTPS
HTTP (HyperText Transfer Protocol) и HTTPS (HTTP Secure) работают поверх TCP. Каждый HTTP-запрос требует надёжной доставки: потеря даже одного байта HTML, CSS или JSON приведёт к повреждению документа. TCP гарантирует, что весь ответ сервера дойдёт до клиента целиком и в правильном порядке.
В HTTP/1.1 и HTTP/2 поверх одного TCP-соединения мультиплексируется множество запросов. В HTTP/3 (разработан Google как QUIC) используется UDP с собственным механизмом надёжности, реализованным в пространстве пользователя, а не в ядре ОС. Это позволяет устранить head-of-line blocking на уровне TCP и сократить задержку за счёт отсутствия рукопожатия при смене сети (например, переход с Wi-Fi на мобильный интернет).
DNS
DNS (Domain Name System — система доменных имён) изначально использовала UDP для запросов. UDP идеален здесь, потому что запросы и ответы обычно помещаются в одну датаграмму (до 512 байт в классическом DNS, до 4096 с EDNS). Низкая задержка критична: каждое обращение к веб-странице может требовать нескольких DNS-запросов, и добавление TCP-рукопожатия замедлило бы загрузку. Если ответ DNS превышает размер датаграммы или требуется надёжность (zone transfer), DNS переключается на TCP.
Видеозвонки и потоковое видео
Видеозвонки (WebRTC, Zoom, Skype) и потоковое видео в реальном времени (Twitch, YouTube Live) используют UDP. Задержка здесь важнее полноты: если один кадр видео потерян, лучше показать следующий кадр сразу, чем ждать повторную передачу старого. Повторная передача привела бы к "заморозке" изображения, что хуже, чем кратковременное артефактное изображение. Протоколы вроде RTP (Real-time Transport Protocol) работают поверх UDP и добавляют нумерацию пакетов и временные метки, но не повторную передачу.
Онлайн-игры
Многопользовательские онлайн-игры используют UDP для передачи состояния игрового мира (позиции игроков, выстрелы). Потеря одного пакета с координатами не критична: следующий пакет через 16 мс (60 FPS) содержит актуальные координаты. TCP здесь непригоден, потому что задержка в 100 мс на повторную передачу старого пакета сделала бы игру неиграбельной. Однако важные команды (покупка предмета, авторизация) могут отправляться по TCP или с собственным механизмом подтверждений поверх UDP.
IoT и телеметрия
Устройства интернета вещей (IoT — Internet of Things), датчики и системы телеметрии часто используют UDP или MQTT (Message Queuing Telemetry Transport) поверх TCP. MQTT — лёгкий протокол публикации-подписки, оптимизированный для нестабильных сетей и устройств с ограниченными ресурсами. В чистом виде UDP используется, когда потеря отдельных показаний датчика допустима, а экономия энергии и трафика приоритетна.
Java NIO: эффективная работа с сетью
Классические блокирующие сокеты
NIO (New I/O, пакет
#Java #для_новичков #beginner #IO #NIO #Ip #Port #TCP #UDP
HTTP (HyperText Transfer Protocol) и HTTPS (HTTP Secure) работают поверх TCP. Каждый HTTP-запрос требует надёжной доставки: потеря даже одного байта HTML, CSS или JSON приведёт к повреждению документа. TCP гарантирует, что весь ответ сервера дойдёт до клиента целиком и в правильном порядке.
В HTTP/1.1 и HTTP/2 поверх одного TCP-соединения мультиплексируется множество запросов. В HTTP/3 (разработан Google как QUIC) используется UDP с собственным механизмом надёжности, реализованным в пространстве пользователя, а не в ядре ОС. Это позволяет устранить head-of-line blocking на уровне TCP и сократить задержку за счёт отсутствия рукопожатия при смене сети (например, переход с Wi-Fi на мобильный интернет).
DNS
DNS (Domain Name System — система доменных имён) изначально использовала UDP для запросов. UDP идеален здесь, потому что запросы и ответы обычно помещаются в одну датаграмму (до 512 байт в классическом DNS, до 4096 с EDNS). Низкая задержка критична: каждое обращение к веб-странице может требовать нескольких DNS-запросов, и добавление TCP-рукопожатия замедлило бы загрузку. Если ответ DNS превышает размер датаграммы или требуется надёжность (zone transfer), DNS переключается на TCP.
Видеозвонки и потоковое видео
Видеозвонки (WebRTC, Zoom, Skype) и потоковое видео в реальном времени (Twitch, YouTube Live) используют UDP. Задержка здесь важнее полноты: если один кадр видео потерян, лучше показать следующий кадр сразу, чем ждать повторную передачу старого. Повторная передача привела бы к "заморозке" изображения, что хуже, чем кратковременное артефактное изображение. Протоколы вроде RTP (Real-time Transport Protocol) работают поверх UDP и добавляют нумерацию пакетов и временные метки, но не повторную передачу.
WebRTC (Web Real-Time Communication) — это открытый фреймворк для организации передачи потоковых данных, голосовых вызовов и видеоконференций между браузерами и приложениями без установки плагинов. Он использует UDP для передачи медиа-потоков через протокол SRTP (Secure RTP).
Онлайн-игры
Многопользовательские онлайн-игры используют UDP для передачи состояния игрового мира (позиции игроков, выстрелы). Потеря одного пакета с координатами не критична: следующий пакет через 16 мс (60 FPS) содержит актуальные координаты. TCP здесь непригоден, потому что задержка в 100 мс на повторную передачу старого пакета сделала бы игру неиграбельной. Однако важные команды (покупка предмета, авторизация) могут отправляться по TCP или с собственным механизмом подтверждений поверх UDP.
IoT и телеметрия
Устройства интернета вещей (IoT — Internet of Things), датчики и системы телеметрии часто используют UDP или MQTT (Message Queuing Telemetry Transport) поверх TCP. MQTT — лёгкий протокол публикации-подписки, оптимизированный для нестабильных сетей и устройств с ограниченными ресурсами. В чистом виде UDP используется, когда потеря отдельных показаний датчика допустима, а экономия энергии и трафика приоритетна.
Java NIO: эффективная работа с сетью
Классические блокирующие сокеты
java.net.Socket и ServerSocket создают отдельный поток на каждое соединение. При 10 000 одновременных клиентах это означает 10 000 потоков — огромный расход памяти на стеки и переключение контекста CPU.NIO (New I/O, пакет
java.nio) решает эту проблему через неблокирующие каналы (non-blocking channels) и селекторы (selectors).public class NioServer {
public static void main(String[] args) throws Exception {
// ServerSocketChannel — неблокирующий серверный канал
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false); // неблокирующий режим
// Selector — мультиплексор, который мониторит множество каналов
Selector selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// select() блокирует до появления событий на любом из зарегистрированных каналов
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove(); // обязательно удаляем обработанный ключ
if (key.isAcceptable()) {
// Новое входящее соединение
SocketChannel client = serverChannel.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// Данные доступны для чтения
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = client.read(buffer);
if (bytesRead == -1) {
client.close(); // соединение закрыто клиентом
} else {
buffer.flip(); // переключаем буфер в режим чтения
// обработка данных...
}
}
}
}
}
}Канал (Channel) в NIO — это абстракция для ввода-вывода, которая отличается от потоков (Stream) тем, что поддерживает неблокирующий режим и может работать в обе стороны (чтение и запись). SocketChannel — это канал для TCP-соединения, DatagramChannel — для UDP.
Селектор (Selector) — это механизм мультиплексирования ввода-вывода. Один поток может мониторить множество каналов, ожидая событий (готовность к чтению, записи, подключению). Это позволяет обслуживать тысячи соединений одним или несколькими потоками вместо одного потока на соединение.
SelectionKey — это токен, представляющий зарегистрированный канал в селекторе. Он хранит информацию о канале, селекторе и интересующих операциях (OP_ACCEPT, OP_CONNECT, OP_READ, OP_WRITE).
#Java #для_новичков #beginner #IO #NIO #Ip #Port #TCP #UDP
👍3
Путь байтов в памяти JVM при сетевом взаимодействии
Сетевой ввод-вывод в Java проходит через сложную цепочку от сетевой карты до кучи JVM и обратно. Понимание этого пути критично для оптимизации производительности и управления памятью.
1. От сетевой карты до ядра ОС
Когда пакет приходит на сетевой интерфейс, NIC (Network Interface Controller — сетевой контроллер) генерирует аппаратное прерывание. Драйвер сетевой карты в ядре ОС обрабатывает прерывание, копирует пакет из буфера NIC в кольцевой буфер (ring buffer) ядра — структуру данных фиксированного размера в оперативной памяти, организованную по принципу FIFO (First In, First Out — первым пришёл, первым вышел). Затем стек TCP/IP ядра обрабатывает пакет: проверяет IP-заголовок, TCP-заголовок, вычисляет checksum, обновляет состояние соединения.
Данные приложения из TCP-сегментов накапливаются в сокет-буфере (socket receive buffer) ядра — области памяти ядра, выделенной для конкретного сокета. Размер этого буфера настраивается через опции сокета
2. Из ядра в JVM: read() и ByteBuffer
Когда Java-приложение вызывает
Здесь критично различие между двумя типами
3. Работа GC с сетевыми буферами
Объект
Однако Cleaner срабатывает только при сборке мусора. Если приложение активно выделяет
4. Путь отправки данных
При записи (
Данные из
Стек TCP ядра сегментирует данные, добавляет заголовки TCP/IP, вычисляет checksum.
Сегменты попадают в очередь передачи NIC и отправляются в сеть.
При получении ACK от получателя ядро освобождает соответствующие сегменты из send buffer.
Если send buffer заполнен (получатель не успевает читать), вызов
5. Объекты сетевого стека в JVM
При использовании NIO с Selector в куче JVM хранятся:
Объект
Объекты
Объекты
Эти объекты лёгкие и живут в Young Generation. При закрытии канала (
#Java #для_новичков #beginner #IO #NIO #Ip #Port #TCP #UDP
Сетевой ввод-вывод в Java проходит через сложную цепочку от сетевой карты до кучи JVM и обратно. Понимание этого пути критично для оптимизации производительности и управления памятью.
1. От сетевой карты до ядра ОС
Когда пакет приходит на сетевой интерфейс, NIC (Network Interface Controller — сетевой контроллер) генерирует аппаратное прерывание. Драйвер сетевой карты в ядре ОС обрабатывает прерывание, копирует пакет из буфера NIC в кольцевой буфер (ring buffer) ядра — структуру данных фиксированного размера в оперативной памяти, организованную по принципу FIFO (First In, First Out — первым пришёл, первым вышел). Затем стек TCP/IP ядра обрабатывает пакет: проверяет IP-заголовок, TCP-заголовок, вычисляет checksum, обновляет состояние соединения.
Данные приложения из TCP-сегментов накапливаются в сокет-буфере (socket receive buffer) ядра — области памяти ядра, выделенной для конкретного сокета. Размер этого буфера настраивается через опции сокета
SO_RCVBUF.2. Из ядра в JVM: read() и ByteBuffer
Когда Java-приложение вызывает
SocketChannel.read(buffer), происходит переход из пользовательского пространства в пространство ядра (system call). Данные копируются из сокет-буфера ядра в буфер JVM.Здесь критично различие между двумя типами
ByteBuffer:HeapByteBuffer — буфер, размещённый в куче JVM (Heap). При чтении из канала данные сначала копируются во временный буфер в нативной памяти (выделенный JNI), а затем — в массив byte[] в куче. Это двойное копирование снижает производительность.
DirectByteBuffer — буфер, размещённый в нативной памяти (native memory, вне кучи JVM). При чтении данные копируются напрямую из сокет-буфера ядра в нативную память, минуя кучу. Это устраняет одно копирование и позволяет использовать zero-copy техники на уровне ОС.
// HeapByteBuffer: данные в куче, медленнее при I/O
ByteBuffer heapBuffer = ByteBuffer.allocate(1024);
// DirectByteBuffer: данные в нативной памяти, быстрее при I/O
ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024);
Zero-copy — это техника, при которой данные не копируются между буферами в пользовательском пространстве, а передаются по ссылке или напрямую из ядра в целевой буфер. В Java FileChannel.transferTo() и transferFrom() используют zero-copy для передачи данных между файлами и сокетами без промежуточного буфера в пользовательском пространстве.
3. Работа GC с сетевыми буферами
Объект
ByteBuffer в Java — это обёртка. Для HeapByteBuffer он содержит ссылку на byte[] в куче. Для DirectByteBuffer он содержит адрес в нативной памяти (поле address типа long). Сам объект DirectByteBuffer — маленький объект в куче (десятки байтов), но он ссылается на большой блок нативной памяти (мегабайты).Cleaner — это механизм в JVM, использующий PhantomReference (фантомную ссылку) для регистрации callback-функции, которая вызывается, когда объект становится пригодным для сборки мусора. Когда DirectByteBuffer собирается GC, Cleaner вызывает нативный метод free(), который освобождает блок нативной памяти через Unsafe.freeMemory().
PhantomReference — это тип ссылки в Java, который позволяет узнать, что объект был финализирован сборщиком мусора, но ещё не удалён. В отличие от WeakReference и SoftReference, phantom reference не даёт доступа к объекту, но гарантирует, что объект уже недостижим.
Однако Cleaner срабатывает только при сборке мусора. Если приложение активно выделяет
DirectByteBuffer, но GC не запускается (потому что куча не заполнена), нативная память может исчерпать лимит ОС, вызывая OutOfMemoryError: Direct buffer memory. Чтобы избежать этого, важно явно вызывать cleaner.clean() (через рефлексию) или использовать пулы буферов (например, Netty ByteBuf), которые переиспользуют выделенную память.4. Путь отправки данных
При записи (
SocketChannel.write(buffer)) путь обратный:Данные из
ByteBuffer (куча или нативная память) копируются в сокет-буфер отправки ядра (socket send buffer).Стек TCP ядра сегментирует данные, добавляет заголовки TCP/IP, вычисляет checksum.
Сегменты попадают в очередь передачи NIC и отправляются в сеть.
При получении ACK от получателя ядро освобождает соответствующие сегменты из send buffer.
Если send buffer заполнен (получатель не успевает читать), вызов
write() вернёт 0 записанных байт в неблокирующем режиме или заблокирует поток в блокирующем режиме.5. Объекты сетевого стека в JVM
При использовании NIO с Selector в куче JVM хранятся:
Объект
Selector — содержит ссылку на нативную структуру pollfd (Linux) или WSAPOLL (Windows).Объекты
SelectionKey — хранятся в HashSet внутри Selector, по одному на каждый зарегистрированный канал.Объекты
SocketChannel и ServerSocketChannel — обёртки над файловыми дескрипторами ОС.Эти объекты лёгкие и живут в Young Generation. При закрытии канала (
channel.close()) файловый дескриптор освобождается нативным кодом, а Java-объект становится мусором для следующей Minor GC. Однако если забыть закрыть канал, дескриптор утечёт на уровне ОС — это утечка файлового дескриптора (file descriptor leak), которая при масштабе приводит к исчерпанию лимита ulimit -n и невозможности открыть новые соединения.// Правильный паттерн: try-with-resources для автоматического закрытия
// Closeable — интерфейс, требующий реализации метода close()
try (SocketChannel channel = SocketChannel.open(new InetSocketAddress("host", 80))) {
ByteBuffer buffer = ByteBuffer.allocateDirect(4096);
channel.read(buffer);
} // channel.close() вызывается автоматически, освобождая файловый дескриптор
#Java #для_новичков #beginner #IO #NIO #Ip #Port #TCP #UDP
👍3
Что выведет код?
#Tasks
import java.net.InetAddress;
public class Task140826 {
public static void main(String[] args) throws Exception {
InetAddress addr = InetAddress.getByName("");
System.out.println(addr.getHostAddress());
}
}
#Tasks
👍1
👍1
Что такое 🤓
Ответ:
JPQL — это объектно-ориентированный язык запросов, похожий на SQL, но работающий с сущностями и их полями, а не с таблицами и колонками.
Пример: SELECT u FROM User u WHERE u.age > 18.
Поддерживает JOIN, GROUP BY, ORDER BY, агрегации. Отличается от нативного SQL тем, что не зависит от конкретной СУБД.
Поддерживает параметры: :name (named) или ?1 (positional). Используется с EntityManager.createQuery().
Для сложных запросов можно использовать Criteria API или нативные запросы (@NativeQuery ).
#собеседование
JPQL (Java Persistence Query Language)? Ответ:
JPQL — это объектно-ориентированный язык запросов, похожий на SQL, но работающий с сущностями и их полями, а не с таблицами и колонками.
Пример: SELECT u FROM User u WHERE u.age > 18.
Поддерживает JOIN, GROUP BY, ORDER BY, агрегации. Отличается от нативного SQL тем, что не зависит от конкретной СУБД.
Поддерживает параметры: :name (named) или ?1 (positional). Используется с EntityManager.createQuery().
Для сложных запросов можно использовать Criteria API или нативные запросы (
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
15 августа (дата отмечается как Computer Science Day) — день, посвящённый дате запуска первого массового электронного компьютера ENIAC.
Лесли Джон Комри (15 августа 1893 г. – 11 декабря 1950 г.) — Астроном и пионер механической/механографической автоматизации вычислений; один из ранних организаторов коммерческих вычислительных услуг и автоматизации таблиц — предтеча компьютерной обработки данных.
Пьер Буге́р (также Буге; фр. Pierre Bouguer; 16 февраля 1698, Круазик (Croisic), Франция — 15 августа 1758, Париж) — французский физик, математик и астроном, основатель фотометрии. Известен трудами по теории корабля, геодезии, гидрографии и другим отраслям знания. Имя Бугера внесено в список 72 величайших учёных Франции, размещённый на первом этаже Эйфелевой башни.
1877 — американский изобретатель Томас Эдисон в письме президенту телеграфной компании Питтсбурга предложил в качестве приветствия при общении по телефону использовать слово «hello» (в России оно трансформировалось в «алло»). В этот же день Эдисон произвёл первую запись звука на свой фонограф — песню «Mary Had a Little Lamb» («У Мэри был барашек»).
1977 — радиотелескоп Big Ear (Огайо, США) зафиксировал "Wow! signal" — один из самых известных возможно внеземных радиоимпульсов.
1998 — компания Apple начала поставки iMac G3, модели, которая кардинально изменила дизайн и восприятие компьютеров в массовом сознании.
#Biography #Birth_Date #Events #15Августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Напоминаю, что продолжаю набирать желающих изучить Java!
Устройств на работу не обещаю, но до мидла (java/spring) доведу.
Пишите @Oleborn
Устройств на работу не обещаю, но до мидла (java/spring) доведу.
Пишите @Oleborn
🤓2
Христос Харилаос Пападимитриу (греч. Χρήστος Χαριλάος Παπαδημητρίου; род. 1949, Афины) — один из ведущих теоретиков в компьютерных науках; важные работы по теории алгоритмов, сложности вычислений и теория игр, автор фундаментальных учебников и исследований. Член Национальных Академии наук (2009) и Инженерной академии США, профессор Калифорнийского университета в Беркли.
1890 — Электромеханическая обработка переписи США: Бюро переписи объявляет результаты, подсчитанные машинами Германа Холлерита — рубеж для истории вычислений и табуляторов.
1993 — Иан Мёрдок основал сообщество «Debian», занимающееся созданием и распространением свободного дистрибутива Debian GNU/Linux.
2006 — в русской Википедии появилась юбилейная, 100-тысячная статья.
#Biography #Birth_Date #Events #16Августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Софт-скиллы, которым не учат в курсах
Вот представь, ты прочитал весь мой канал, изучил синтаксис вдоль и поперек, научился виртуозно делать API, освоил Git, знаешь Spring и WebFlux.
Но вот пришло собеседование — и ты... завис.
— Расскажите о себе.
— Ну… я... типа… учился… кодить...
Знакомо?
А теперь еще предположим: ты уже устроился и тебе дали таску.
И ты видишь, что надо уточнить у тимлида детали.
Но в голове:
«А если я спрошу — подумает, что тупой...»
«Лучше погуглю еще 3 часа, чем покажусь нубом»
«Он ведь профи. Я даже не знаю с чего начать...»
Это называется - коммуникативная тревожность.
Она же — тихий киллер карьеры в IT.
Почему ты боишься говорить
Вот тебе правда: страх общения — это не про характер.
Это навык.
Даже самые «разговорчивые» разработчики когда-то:
- боялись скинуть Pull Request с комментариями,
- часами переписывали сообщение в телеграмме,
- репетировали простой вопрос голосом.
Почему некоторым в IT это так сложно?
Потому что IT часто привлекает интровертов, бывших «отличников», людей, которые учились всё понимать сами, без помощи. И теперь, оказавшись в команде — они просто не умеют задавать вопросы или входить в беседу.
Что происходит в голове?
В когнитивной психологии есть понятие self-presentation concern — это тревога из-за того, как тебя воспримут другие.
Именно она:
- заставляет молчать, когда нужно спросить;
- мешает делиться идеями;
- блокирует на стендапах.
А ещё есть спираль молчания — если ты боишься говорить, ты выпадаешь из общения, и из-за этого боишься ещё больше.
Вот пара моих советов если ты чувствуешь что твой софт-скилл слабоват:
Говори, даже если страшно.
Но не вживую, а письменно.
Заведи привычку активно писать: в рабочем чате, в Telegram, в комментариях к pull request'ам.
Так ты приучаешь мозг к выражению мысли — без страха, что тебя перебьют или осудят.
Это снижает тревожность, активирует рефлексивную речь — внутреннее проговаривание и структуру мысли.
Не бойся задавать глупые вопросы.
Как сказал один умный человек: "В IT нет глупых вопросов, есть чересчур ЧСВ-шные отвечающие"
Микроконтакт — это уже общение
Не нужно фигачить речь на 3 минуты.
Просто начни с одной фразы:
«А почему мы сделали вот так, а не так?»
«Спасибо, крутая реализация»
«Подскажи, я что-то путаюсь в этой части»
Это называется anchored small talk — микровзаимодействия, которые создают эффект «я в теме». Даже если ты мало говоришь.
Заготовь фразы. Да, можно и записать
Серьёзно.
Напиши себе в заметках:
Вопрос на стендап: «Ребят, я правильно понимаю, что…»
Начало диалога: «Можно короткий вопрос про фичу?»
Завершение: «Окей, тогда попробую и отпишусь»
В момент тревоги мозг не придумывает речь с нуля. Он вытаскивает готовое.
Подсунь ему нужные заготовки — и увидишь, как снижается стресс.
Найди «одного своего»
Не команду. Не менторов. Одного союзника, с кем безопасно говорить.
Пишете вместе код — обменивайтесь мыслями.
Работаете на проекте — обсуждай идеи.
В сообществе — шутите, делитесь опытом.
Это снижает страх перед всей группой. Есть ощущение, что ты не один. А с этого и начинается уверенное взаимодействие.
Ты можешь спросить: "А зачем мне это вообще?"
Пойми:
Ты можешь быть классным кодером, но без софт-скиллов — останешься «интровертным сеньором без влияния».
Ты сможешь влиять, если умеешь объяснить, услышать, вдохновить.
Продуктивность команд напрямую зависит от психологической безопасности — и ты можешь её самостоятельно формировать.
А еще спроси себя - кого повысят, из двух одинаково скиловых разработчиков? Того кто грамотно и без страха излагает свои мысли или того кто молчит или отвечает невпопад?
Поэтому, не стесняйся, пиши в комментариях, что ты думаешь об это статье! Прокачай навык
#motivation
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
https://hh.ru/vacancy/135709779
Я вот не понимаю, неужто кто-то соглашается на такие условия?🤪
Крутая, бл, команда.... 🤦♂️
Я вот не понимаю, неужто кто-то соглашается на такие условия?
Крутая, бл, команда.... 🤦♂️
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯1