TCP и UDP: в чём разница и что на самом деле проверяет мониторинг порта
Два транспортных протокола делят между собой почти весь интернет: TCP везёт сайты, почту и базы данных, UDP — DNS, звонки, игры, VPN и HTTP/3. Разбираем, чем они отличаются на уровне заголовков и рукопожатия, какие сервисы на чём работают, почему TCP-порт проверяется одной командой, а UDP-порт извне «проверить» нельзя — и что это значит для мониторинга.
TCP (Transmission Control Protocol, RFC 9293) — транспортный протокол с установлением соединения: перед передачей данных стороны обмениваются тремя сегментами, каждый байт нумеруется, подтверждается и при потере отправляется повторно, поэтому приложение получает данные без потерь и в исходном порядке. UDP (User Datagram Protocol, RFC 768) — транспортный протокол без соединения: датаграмма уходит адресату сразу, без рукопожатия, подтверждений и повторов, и если она потерялась или пришла позже соседней, транспорт об этом не сообщит. За надёжность TCP платит минимум одним круговым обходом до первого байта данных и 20 байтами заголовка против 8 у UDP.
Чем отличается TCP от UDP: сводная таблица
Главное отличие — TCP берёт надёжность на себя, а UDP оставляет её приложению; рукопожатие, заголовок, контроль перегрузки и задержка — следствия этого выбора. Оба работают на транспортном уровне и делят одно пространство портов 0–65535 (что такое порт — в отдельной статье, место транспорта в стеке — в разборе модели OSI на примере сайта).
| Критерий | TCP | UDP |
|---|---|---|
| Соединение | Есть: SYN → SYN-ACK → ACK, закрытие через FIN или RST | Нет: первая же датаграмма несёт данные |
| Гарантия доставки | Да: номера последовательности, ACK, ретрансмит по таймеру (начальный RTO 1 с по RFC 6298) и по дублирующим ACK | Нет: транспорт потерю не замечает |
| Порядок | Сохраняется: приложение читает непрерывный поток байтов | Не гарантируется; зато сохраняются границы сообщений |
| Контроль потока и перегрузки | Окно приёмника (16 бит, до 65 535 байт; с масштабированием по RFC 7323 — до 1 ГиБ) плюс cwnd отправителя (CUBIC, BBR) | Нет: отправитель шлёт с любой скоростью (RFC 8085 лишь рекомендует сдерживаться) |
| Размер заголовка | 20 байт без опций, до 60 с опциями (MSS, SACK, timestamps, wscale) | 8 байт: два порта, длина, контрольная сумма |
| Накладные расходы | 3 сегмента до данных, состояние в памяти обеих сторон, ACK на каждые 1–2 сегмента | Ноль служебных пакетов, состояния нет |
| Задержка до первого байта | Минимум 1 RTT на рукопожатие (плюс 1 RTT на TLS 1.3) | 0 RTT: данные в первом пакете |
| Типичное применение | Веб (HTTP/1.1, HTTP/2), почта, SSH, базы данных, файлы | DNS, NTP, DHCP, VoIP, игры, VPN, HTTP/3 |
Как устанавливается TCP-соединение и почему в UDP рукопожатия нет
TCP-соединение открывается тремя сегментами: клиент шлёт SYN со своим начальным номером последовательности, сервер отвечает SYN-ACK со своим номером и подтверждением клиентского, клиент завершает обмен ACK. После этого обе стороны знают, что порт слушает, а стеки договорились о номерах, MSS и масштабе окна. UDP этого не делает, потому что ему нечего согласовывать: нет номеров, окон и состояния.
| Шаг | TCP | UDP |
|---|---|---|
| 1 | Клиент → сервер: SYN, seq=x (плюс MSS, SACK, wscale) | Клиент → сервер: датаграмма с данными (DNS-запрос, 29 байт) |
| 2 | Сервер → клиент: SYN-ACK, seq=y, ack=x+1 | Сервер → клиент: ответ — если приложение захотело ответить |
| 3 | Клиент → сервер: ACK, ack=y+1 — состояние ESTABLISHED | — |
| Порт закрыт | Сервер → клиент: RST (RFC 9293: reset на любой сегмент к несуществующему соединению) | Ядро сервера шлёт ICMP Port Unreachable (тип 3, код 3) — если ICMP не зарезан |
$ sudo tcpdump -ni eth0 'host 203.0.113.10 and (port 443 or port 53)'
# пример вывода: рукопожатие TCP — три сегмента, length 0
10:14:02.118 IP 198.51.100.7.51422 > 203.0.113.10.443: Flags [S],
seq 1938413052, win 64240, options [mss 1460,sackOK,wscale 7], length 0
10:14:02.141 IP 203.0.113.10.443 > 198.51.100.7.51422: Flags [S.],
seq 771302910, ack 1938413053, win 65160, options [mss 1460], length 0
10:14:02.141 IP 198.51.100.7.51422 > 203.0.113.10.443: Flags [.],
ack 1, win 502, length 0
# пример вывода: UDP — запрос и ответ, никакого рукопожатия
10:14:05.002 IP 198.51.100.7.40321 > 203.0.113.10.53:
41235+ A? example.com. (29)
10:14:05.019 IP 203.0.113.10.53 > 198.51.100.7.40321:
41235 1/0/0 A 93.184.215.14 (45)
23 мс между SYN и SYN-ACK — RTT до сервера, столько TCP «теряет» перед первым байтом; HTTPS добавляет ещё RTT на TLS 1.3. QUIC (RFC 9000, май 2021) поверх UDP встраивает TLS 1.3 в свой хендшейк и укладывается в один RTT, при повторном подключении — в ноль.
Какие протоколы работают поверх TCP, а какие поверх UDP
Правило выбора: если потеря данных недопустима, а лишние 20–50 мс не критичны — TCP; если свежий пакет ценнее старого (голос, видео, игры) или обмен — один короткий запрос и ответ (DNS, NTP) — UDP. Сводка на сентябрь 2026, порты — из реестра IANA.
| Протокол / сервис | Транспорт | Порт | Примечание |
|---|---|---|---|
| HTTP/1.1 | TCP | 80 | Один запрос за раз на соединение |
| HTTPS (HTTP/1.1, HTTP/2 поверх TLS) | TCP | 443 | HTTP/2 мультиплексирует потоки в одном соединении |
| HTTP/3 (QUIC) | UDP | 443 | RFC 9114; браузер узнаёт о нём из Alt-Svc или DNS-записи HTTPS |
| DNS | UDP, fallback TCP | 53 | Ответ не влез — флаг TC и повтор по TCP; AXFR всегда TCP; по RFC 7766 TCP обязателен |
| DNS over TLS / over QUIC | TCP / UDP | 853 | DoT — RFC 7858, DoQ — RFC 9250 |
| NTP | UDP | 123 | Пакет туда, пакет обратно; ретрансмит лишь исказил бы замер |
| DHCP | UDP | 67 сервер / 68 клиент | Широковещание: у клиента ещё нет IP, TCP невозможен |
| SNMP | UDP | 161 / 162 трапы | Опрос тысяч устройств без тысяч соединений |
| SIP | UDP или TCP | 5060 / 5061 (TLS) | Сигнализация звонка; голос идёт отдельно |
| RTP / SRTP (голос, видео) | UDP | динамические, часто 10000–20000 | Потерять 20 мс голоса дешевле, чем ждать повтор 200 мс |
| WireGuard | UDP | 51820 (по умолчанию) | Молчит без валидного ключа — извне неотличим от закрытого порта |
| OpenVPN | UDP (есть режим TCP) | 1194 | TCP-режим — обход файрволов ценой «TCP поверх TCP» |
| Онлайн-игры | UDP | свои (27015 у Source-игр) | Старый пакет с координатами бесполезен |
| SSH / SFTP | TCP | 22 | Терминал без потерь и порядка невозможен |
| SMTP | TCP | 25 между серверами / 587 отправка / 465 SMTPS | Письмо либо доставлено целиком, либо нет |
| IMAP / POP3 | TCP | 143, 993 / 110, 995 | Долгоживущие сессии с состоянием |
| MySQL / MariaDB | TCP | 3306 | Локально часто unix-сокет, снаружи — только TCP |
| PostgreSQL | TCP | 5432 | То же |
| Redis | TCP | 6379 | Наружу не открывать: аутентификации по умолчанию нет |
| RDP | TCP + UDP | 3389 | Подключение по TCP, поток экрана при возможности — по UDP |
Как проверяется TCP-порт и почему UDP-порт так проверить нельзя
TCP-порт проверяется однозначно: на SYN открытый порт отвечает SYN-ACK, закрытый — RST, молчание означает файрвол с DROP. UDP-порт однозначного ответа не даёт: открытый порт на чужую нагрузку обычно молчит, закрытый отвечает ICMP Port Unreachable, но ICMP часто зарезан или ограничен по частоте — и молчание одинаково означает «открыт», «отфильтрован» и «ICMP не дошёл». Поэтому сканеры пишут для UDP open|filtered.
| Отправили | Что вернул хост | Что это значит | nc / nmap |
|---|---|---|---|
| TCP SYN | SYN-ACK | Порт открыт, приложение слушает | succeeded / open |
| TCP SYN | RST | Хост жив, порт закрыт (никто не слушает или REJECT tcp-reset) | Connection refused / closed |
| TCP SYN | Ничего (после повторов SYN) | Файрвол с DROP, нет маршрута или хост выключен | timed out / filtered |
| UDP-датаграмма | UDP-ответ | Порт открыт и приложение поняло нагрузку (nmap шлёт протокольные пробы для известных портов) | open |
| UDP-датаграмма | ICMP тип 3, код 3 | Хост жив, на порту никто не слушает | closed |
| UDP-датаграмма | ICMP тип 3, код 1, 2, 9, 10 или 13 | Отфильтровано файрволом или маршрутизатором | filtered |
| UDP-датаграмма | Ничего | Открыт, но приложение молчит на чужую нагрузку; или DROP; или ICMP не дошёл (Linux отдаёт unreachable не чаще раза в секунду) | nc: succeeded (!) / nmap: open|filtered |
Отсюда частое заблуждение: nc -zvu пишет «succeeded», и это принимают за доказательство, хотя man-страница OpenBSD-netcat говорит прямо: сканирование с флагами -uz всегда сообщает об успехе независимо от состояния цели. Инструменты для TCP разобраны в статье «Как проверить, открыт ли порт»; ниже — минимум, показывающий разницу.
# TCP: три исхода различимы за одну команду $ nc -zv -w 3 192.0.2.1 443 Connection to 192.0.2.1 443 port [tcp/https] succeeded! $ nc -zv -w 3 192.0.2.1 8443 nc: connect to 192.0.2.1 port 8443 (tcp) failed: Connection refused $ nc -zv -w 3 192.0.2.1 25 nc: connect to 192.0.2.1 port 25 (tcp) timed out: Operation now in progress # UDP: «succeeded» и для DNS, и для порта, где ничего нет $ nc -zvu -w 3 192.0.2.1 53 Connection to 192.0.2.1 53 port [udp/domain] succeeded! $ nc -zvu -w 3 192.0.2.1 5353 Connection to 192.0.2.1 5353 port [udp/mdns] succeeded!
nmap с ключом -sU честнее: ждёт ICMP, повторяет пробы, а для известных портов (53, 123, 161 и других) отправляет осмысленную нагрузку, чтобы получить настоящий ответ приложения. Плата — время: из-за лимита ICMP в Linux полный скан 65 536 UDP-портов, по документации nmap, занимает больше 18 часов.
$ sudo nmap -sU -p 53,123,161,500,5353 192.0.2.1 # пример вывода Starting Nmap 7.95 at 2026-09-25 10:20 MSK Nmap scan report for 192.0.2.1 PORT STATE SERVICE 53/udp open domain 123/udp open|filtered ntp 161/udp open|filtered snmp 500/udp closed isakmp 5353/udp closed zeroconf Nmap done: 1 IP address (1 host up) scanned in 4.87 seconds
Достоверно UDP-порт виден только на самом сервере: ss -ulnp показывает UDP-сокеты в состоянии UNCONN (LISTEN у UDP нет, потому что нет соединения) и процесс, который их держит; -tlnp — TCP-сокеты в LISTEN.
$ sudo ss -ulnp
# пример вывода
State Recv-Q Send-Q Local:Port Peer:Port Process
UNCONN 0 0 0.0.0.0:53 0.0.0.0:* users:(("named",pid=812,fd=20))
UNCONN 0 0 0.0.0.0:123 0.0.0.0:* users:(("chronyd",pid=644,fd=6))
UNCONN 0 0 0.0.0.0:51820 0.0.0.0:*
# у порта 51820 нет процесса: WireGuard живёт в ядре
$ sudo ss -tlnp | grep -E ':(53|5432) '
LISTEN 0 10 0.0.0.0:53 0.0.0.0:* users:(("named",pid=812,fd=21))
LISTEN 0 4096 0.0.0.0:5432 0.0.0.0:* users:(("postgres",pid=1043,fd=6))
Типичные проблемы с UDP: файрвол, NAT, фрагментация и QUIC
Большинство «странных» проблем с UDP сводится к четырём: файрвол пропускает TCP, но режет UDP; NAT забывает UDP-сессию раньше, чем TCP; большой UDP-ответ фрагментируется и теряется; QUIC блокируется, и браузер тихо откатывается на TCP. Общее одно: на сервере ничего не сломано, ss показывает сокет, а извне сервис то работает, то нет.
| Проблема | Симптом | Как проверить | Как исправить |
|---|---|---|---|
| Файрвол пропускает tcp/53, режет udp/53 | dig висит до таймаута, dig +tcp отвечает мгновенно; nc -zv 53 при этом «succeeded» | dig @сервер example.com против dig +tcp @сервер example.com | Открыть udp/53 наряду с tcp/53: в iptables/nftables это два разных правила |
| NAT-таймаут UDP короче TCP | VPN или звонок «замирает» после паузы в 30–120 с, потом оживает | Linux conntrack по умолчанию: UDP 30 с (120 с для двунаправленного потока), TCP established — 5 суток | Keepalive короче таймаута: у WireGuard PersistentKeepalive = 25 |
| Фрагментация больших DNS-ответов | Короткие ответы приходят, DNSSEC-домены и длинные TXT — нет; SERVFAIL или таймауты | dig +bufsize=1232 против dig +bufsize=4096; смотреть флаг tc | EDNS buffer 1232 (DNS Flag Day 2020) и открытый tcp/53 для fallback |
| QUIC заблокирован (udp/443) | Сайт открывается, но первый заход медленнее; в DevTools протокол h2 вместо h3; изредка ERR_QUIC_PROTOCOL_ERROR | Столбец Protocol во вкладке Network; curl --http3-only -I | Открыть udp/443 в обе стороны или осознанно выключить h3 и Alt-Svc на сервере |
DNS показателен: RFC 1035 ограничил UDP-ответ 512 байтами, EDNS0 разрешил больше, но ответ на 4 КБ разбивается на IP-фрагменты, которые файрволы часто отбрасывают. Поэтому с 1 октября 2020 года (DNS Flag Day) серверы договорились о буфере 1232 байта — MTU 1280 по требованию IPv6 минус 48 байт заголовков. Что не влезло, уходит с флагом TC, и клиент переспрашивает по TCP; если tcp/53 закрыт, домен резолвится «через раз».
# UDP-запрос: ответ обрезан, стоит флаг tc — резолвер повторит по TCP $ dig +noall +comments +bufsize=512 @192.0.2.1 example.com DNSKEY ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5211 ;; flags: qr tc rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1 # Тот же запрос по TCP: ответ целиком $ dig +noall +comments +tcp @192.0.2.1 example.com DNSKEY ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1 # Если tcp/53 закрыт файрволом — вот что увидит резолвер $ dig +tcp @192.0.2.1 example.com DNSKEY ;; communications error to 192.0.2.1#53: connection refused
С QUIC откат почти незаметен: при неудаче QUIC-хендшейка Chromium помечает h3 для хоста как неработающий и ходит по TCP, пользователь платит лишним RTT на первом заходе. Если браузер всё же показывает ERR_QUIC_PROTOCOL_ERROR — это тема отдельной статьи.
Что проверяет мониторинг порта и как контролировать UDP-службы
Проверка «Порт» в мониторинге — это TCP-подключение: SYN, ожидание SYN-ACK, закрытие. Она отвечает на один вопрос — принимает ли хост соединения на этом порту — и подходит для SSH, SMTP, MySQL, PostgreSQL или порта своего приложения. Аналогичной проверки для UDP не существует: отсутствие ICMP unreachable ничего не доказывает. В Пруфене проверка порта устанавливает TCP-соединение с заданным портом из 20 точек мониторинга — 17 в России, а также Минск, Астана и Испания — с интервалом от 2 минут. Инцидент открывается, когда подключение не проходит с заданной доли точек: так отсеиваются сбои сети одной площадки. UDP-порты эта проверка не тестирует — и не делает вид, что тестирует.
UDP-службы контролируют на прикладном уровне: задают сервису настоящий вопрос и сверяют ответ. Для DNS это проверка DNS: она делает реальный запрос записей домена, и если udp/53 закрыт или сервер отдаёт не то, проверка это увидит — в отличие от порт-скана, которому UDP 53 всегда покажется «открытым». Тот же принцип для любого UDP-сервиса: NTP проверяют запросом времени, VPN — установлением туннеля, а не тем, что порт не ответил ICMP.
Пруфен объединяет в одной проверке несколько типов: TCP-порт для базы и SSH, HTTP для сайта, DNS для домена. Уведомление приходит в Email, Telegram или Макс, когда проверка перестала проходить, и второе — когда восстановилась; если ресурс так и не поднялся, подключается голосовой звонок. Время обнаружения равно интервалу проверки. Бесплатный план включает 5 проверок, при регистрации на баланс начисляется 150 ₽.
Частые вопросы
Почему DNS работает на UDP, а не на TCP?
Типичный обмен — запрос на 30–50 байт и ответ до нескольких сотен. По TCP это стоило бы рукопожатия, закрытия и состояния на сервере под каждого из миллионов клиентов; по UDP — ровно два пакета, а потерю резолвер лечит повтором сам. TCP при этом обязателен по RFC 7766: на него переходят при усечённом ответе (флаг TC) и для трансфера зон.
UDP действительно быстрее TCP?
Быстрее до первого байта: нет рукопожатия — минус один RTT, и нет остановок на ретрансмит. По пропускной способности на чистом канале разницы почти нет: 12 байт разницы в заголовке при кадре 1500 байт — меньше 1 %. Зато UDP-приложение без своего контроля перегрузки при потерях может забить канал себе и соседям — поэтому QUIC реализует его поверх UDP заново (RFC 9002).
Можно ли достоверно проверить UDP-порт извне?
Только зная протокол: отправить запрос, на который сервис обязан ответить, — DNS-запрос на 53, NTP-запрос на 123, SNMP GET на 161 с правильным community. Ответ пришёл — порт открыт; не пришёл — неизвестно. Универсальной пустой пробы, как SYN для TCP, у UDP нет. Для WireGuard, который молчит на всё без валидного ключа, извне не доказать даже факт существования сервиса.
HTTP/3 — это UDP? Значит, сайт может терять данные?
HTTP/3 работает поверх QUIC, а QUIC — поверх UDP, но надёжность не теряется: QUIC сам нумерует пакеты, подтверждает, повторяет потерянные и управляет перегрузкой — делает поверх UDP всё, что TCP делает в ядре. Выигрыш — один RTT на защищённое соединение вместо двух, и потеря пакета тормозит один поток, а не всю страницу. Данные доходят целиком и в порядке.