Что такое порт и сокет и как ОС различает соединения?
Модели OSI и TCP/IP
Порт — 16-битный номер (0–65535), адресующий приложение внутри хоста; сокет — объект ОС, конечная точка соединения. TCP-соединение однозначно задаёт четвёрка: IP и порт клиента, IP и порт сервера.
Порты
- 0–1023 — well-known (22, 80, 443), на Linux для bind нужны привилегии.
- 1024–49151 — registered: 5432 у PostgreSQL, 6379 у Redis.
- Эфемерные выдаёт ОС для исходящих соединений; в Linux по умолчанию 32768–60999.
Слушающий и подключённые сокеты
- Сервер делает
bindиlistenна 8080 — это один listening-сокет. - Каждый
acceptвозвращает новый сокет со своим 4-tuple, и у всех локальный порт 8080. Поэтому один порт обслуживает сотни тысяч клиентов. - Ядро ищет сокет по точному совпадению 4-tuple, а новые SYN отдаёт слушающему.
// сырых сокетов в браузере нет, но видно, открывал ли запрос новое соединение
for (const url of ['/api/a', '/api/b']) await fetch(url).then((r) => r.text()); // запись — после чтения тела
for (const e of performance.getEntriesByType('resource')) {
if (!e.connectStart) continue; // чужой origin без Timing-Allow-Origin — нули
const reused = e.connectStart === e.connectEnd; // не было TCP/TLS-рукопожатия
console.log(e.name, e.nextHopProtocol, reused ? 'старый сокет' : 'новый сокет');
}Граничные случаи
- К одному
IP:портможно открыть не больше ~28 тыс. исходящих соединений — ephemeral port exhaustion без пула. - TIME_WAIT держит 4-tuple занятым ~60 с после закрытия.
Коротко для собеседования
Один порт сервера обслуживает множество клиентов, потому что ядро различает соединения по полной четвёрке адресов, а не по порту. Ограничения всплывают на клиенте: без пула соединений к одному хосту кончаются эфемерные порты, а TIME_WAIT держит их после закрытия.