Модель OSI и TCP/IP, TCP и UDP
↑ 1.1 Сети и протоколы для бэкенда · → Следующая: HTTP для бэкенда
Зачем это на собесе
Бэкендер должен понимать, что происходит с запросом ниже HTTP: откуда таймауты, почему «connection reset», зачем keep-alive и пулы соединений, почему gRPC требует HTTP/2. Вопросы про OSI и TCP vs UDP задают на любом бэкенд-собесе.
Подтемы
- Модель OSI и TCP/IP, инкапсуляция
- TCP: handshake, надёжность, flow и congestion control, закрытие соединения
- UDP и где его применяют (QUIC)
- Порты, сокеты, эфемерные порты
- Что это значит для .NET: HttpClient, пулы соединений, таймауты
Объяснение
Модель OSI (7 уровней) и TCP/IP (4 уровня)
| Уровни OSI | Уровень TCP/IP | Примеры |
|---|---|---|
| 7 Прикладной, 6 Представления, 5 Сеансовый | Прикладной | HTTP, gRPC, DNS, SMTP, TLS* |
| 4 Транспортный | Транспортный | TCP, UDP, QUIC |
| 3 Сетевой | Интернет | IP, ICMP |
| 2 Канальный, 1 Физический | Сетевой доступ | Ethernet, Wi-Fi, кабель |
*TLS формально между 4 и 7 уровнем. На практике оперируют моделью TCP/IP, а OSI спрашивают как теорию.
Инкапсуляция: данные приложения → сегмент TCP (порты) → пакет IP (адреса) → кадр Ethernet (MAC).
TCP
- С установкой соединения: 3-way handshake (SYN → SYN-ACK → ACK).
- Надёжность: нумерация байтов, подтверждения (ACK), повторная отправка, контрольные суммы.
- Порядок: получатель собирает поток в правильной последовательности.
- Flow control (окно получателя) и congestion control (slow start, AIMD).
- Закрытие: FIN/ACK в обе стороны. Состояние
TIME_WAITу закрывающей стороны держит порт ~60 с. - Поток байтов, а не сообщений: границы сообщений определяет протокол выше (HTTP Content-Length, gRPC length-prefix).
UDP
- Без соединения, без гарантий доставки и порядка, минимальный заголовок.
- Быстро и без задержки на handshake.
- Применение: DNS, видео и голос, игры, метрики (StatsD), QUIC → HTTP/3 (надёжность реализована поверх UDP).
Порты и сокеты
- Соединение идентифицируется четвёркой: IP и порт клиента, IP и порт сервера.
- Порты: 0–1023 системные (80 HTTP, 443 HTTPS, 5432 PostgreSQL, 8123/9000 ClickHouse, 9092 Kafka, 6379 Redis).
- Клиент получает эфемерный порт. Их число ограничено (~28–60 тыс.), отсюда проблема исчерпания портов при создании нового соединения на каждый запрос.
Что это значит для .NET-разработчика
// ПЛОХО: новый HttpClient на каждый запрос → новые TCP-соединения, TIME_WAIT, исчерпание сокетов
using var client = new HttpClient();
var data = await client.GetStringAsync(url);
// ХОРОШО: IHttpClientFactory переиспользует соединения (пул обработчиков)
builder.Services.AddHttpClient<TerminologyClient>(c => c.BaseAddress = new Uri(cfg["Terminology:Url"]!));- Пул соединений к БД (Npgsql) — по той же причине: handshake TCP, TLS и авторизация дорогие.
- Keep-alive и HTTP/2 мультиплексирование снижают число соединений.
- Таймауты бывают разные: connect (установка TCP), read (ожидание данных), общий на запрос.
Нюансы и подводные камни
Connection refused— на порту никто не слушает (сервис не поднят, не тот порт).Connection timed out— пакеты не доходят (firewall, сеть).Connection reset— соединение оборвала другая сторона или прокси.- Nginx или балансировщик держит свои соединения к бэкенду: таймауты прокси (
proxy_read_timeout) должны быть согласованы с таймаутами приложения. - NAT и балансировщики закрывают «простаивающие» соединения: долгоживущим соединениям (gRPC-стримы, WebSocket) нужны keep-alive пинги.
- В Docker сервисы общаются по именам в общей сети compose, и
localhostвнутри контейнера — это сам контейнер. - MTU и фрагментация — редкая, но реальная причина «висящих» запросов с большими ответами через VPN.
Вопросы с ответами
Назовите уровни модели OSI и где работают HTTP, TCP, IP.
Физический, канальный, сетевой, транспортный, сеансовый, представления, прикладной. HTTP — прикладной, TCP и UDP — транспортный, IP — сетевой.
Чем TCP отличается от UDP? Приведите примеры использования.
TCP — соединение, гарантия доставки и порядка, контроль перегрузки (HTTP/1.1, HTTP/2, БД, gRPC). UDP — без соединения и гарантий, быстрый (DNS, стриминг, игры, QUIC).
Что такое 3-way handshake?
Установка TCP-соединения: клиент шлёт SYN, сервер отвечает SYN-ACK, клиент подтверждает ACK. Стоит один RTT до начала передачи данных.
Почему нельзя создавать new HttpClient на каждый запрос?
Каждый экземпляр открывает свои TCP-соединения. После закрытия сокеты висят в TIME_WAIT, и под нагрузкой кончаются эфемерные порты (socket exhaustion). Нужен IHttpClientFactory или один долгоживущий клиент с SocketsHttpHandler и PooledConnectionLifetime.
Что такое TIME_WAIT и зачем он нужен?
Состояние закрывающей стороны после завершения соединения. Держится около 2·MSL, чтобы опоздавшие пакеты старого соединения не попали в новое с той же четвёркой адресов.
Связанные темы
- Следующая: HTTP для бэкенда: методы, статусы, заголовки, keep-alive, HTTP∕2 и HTTP∕3
- DNS, TCP, TLS со стороны браузера: DNS, TCP, TLS
- HttpClient и IHttpClientFactory: HttpClient и IHttpClientFactory, HeaderPropagation
- gRPC и HTTP/2: gRPC и HTTP∕2: как работает
- Как писать клиента и сервер по TCP: TCP на практике
- Запрос по TCP руками (nc, openssl, Redis): Запрос по TCP руками
- Сети в DevOps: 1.13 Сети — IP, подсети, порты, NAT, firewall
- Диагностика сети: 1.17 Диагностика сети — ping, traceroute, dig, nc, tcpdump