Глава 24 / 51
Том 3 · Разработка протоколов

Сервисы UDP: минимальный драйвер мира без соединений

В UDP нет соединений, рукопожатий и порядка — и драйвер XServer соответственно сходится к одному колбэку. Сердцебиения, протоколы обнаружения и сбор логов — его территория.

Обзор

Позиционирование: самая короткая глава книги — поверхность UDP в XServer минимальна. Акцент на модели отправки 24.3 (отправка целиком ваша) и платформенных деталях 24.4 (яма ICMP на Windows).

24.1 Введение

Семантика UDP — «каждая дейтаграмма самодостаточна»: ни состояния соединения, ни повторов, ни порядка. Драйвер udp в XServer честно отражает это — bind порта, передача каждой прибывшей дейтаграммы вместе с адресом источника, и всё. Понятие сеанса (если нужно) приложение несёт само в содержимом дейтаграммы.

24.2 Один колбэк

EventDgram и структура сообщения
static void EventDgram(XS_HostInfo* pHost, xnetudp* pUdp,
    const xnetudpmessage* pMsg)
{
    /* поля pMsg (xrt_decl.h, дословно):
     *   Remote : адрес источника (заимствован в колбэке)
     *   Data/Size : нагрузка и длина
     *   Flags : XNET_UDP_MESSAGE_TRUNCATED (флаг усечения) и др.
     *   Meta  : метаданные дейтаграммы */
    if ( pMsg->Flags & XNET_UDP_MESSAGE_TRUNCATED ) {
        /* дейтаграмма превысила буфер приёма и усечена — сбросить или залогировать по протоколу */
        return;
    }
    (void)xrtNetUdpSendTo(pUdp, &pMsg->Remote, "ack", 3);
}

Что только что произошло: каждая дейтаграмма запускает один колбэк; каждая дейтаграмма берёт lease текущего поколения через слот слушателя — во время горячей перезагрузки привязка дейтаграмм к старому/новому поколению столь же точна, как у TCP (в reload_matrix есть кейс UDP-всплеска с закрытым пэром).

24.3 Модель отправки

  • Отправка целиком на совести скрипта: xrtNetUdpSendTo(pUdp, адрес цели, данные, длина) — можно ответить источнику, можно отправить любому третьему адресу (сценарии форвардинга/уведомлений)
  • Адрес источника в текст — инструментами семейства адресов xrt (для логов / отладки)
  • Одна отправка = одна дейтаграмма — фрагментация и пересборка прикладного уровня (если нужны) определяются вами
  • recv_limit ограничен 65535 (гл. 07) — естественный потолок одной дейтаграммы

24.4 Платформенные детали

Поведение Windows, которое стоит знать: отправка UDP на уже закрытый порт может вызвать ICMP Port Unreachable от стека пэра, и Windows отражает этот ICMP ошибкой следующего приёма-передачи — выглядит как «отправил на посторонний адрес — свои приём и передача необъяснимо падают». XServer делает для этого изоляцию ICMP-сбросов (отдельный локальный патч в записях версий): спровоцированные ICMP сбросы карантинятся и не задевают последующие дейтаграммы. UDP-кейс reload_matrix покрывает именно это платформенное поведение.

UDP без TLS (ограничение гл. 07) — прикладное шифрование (согласование ключей в протоколе + шифрование нагрузки) разворачивается в практиках XTP2 из гл. 33/41.

24.5 Контракт

  • Заимствование: pMsg (включая Remote/Data) действует в колбэке — перед форвардингом копируйте нужные поля.
  • Отправка: всё отправляется самостоятельно через xrtNetUdpSendTo; границы дейтаграмм гарантирует UDP (целостность содержимого проверяете вы).
  • Поколения: каждая дейтаграмма берёт lease текущего поколения — при перезагрузке новые идут в новое поколение, семантика как у TCP.

Частые ошибки

Ожидание «соединения» поверх UDP
Симптом
Протокол, рассчитанный на порядок и сеансы, после реальных потерь/переупорядочивания ломает автомат состояний.
Причина
UDP не гарантирует ни доставки, ни порядка — сеансы и повторы либо свои (номер последовательности + ACK), либо переходите на TCP.
Игнорирование флага TRUNCATED
Симптом
Случайная обработка полудейтаграммы; невоспроизводимые ошибки контрольных сумм.
Причина
Превышение предела приёма помечается во Flags — без проверки обрывок обрабатывается как целая посылка.

Упражнения

БазовыйОтветчик пульса

На "PING" отвечать "PONG"; остальное отбрасывать.

Приёмка: 100 раундов собственным UDP-клиентом; статистика потерь (на localhost должна быть 0).
ПродвинутыйНадёжный слой с номерами

Реализуйте прикладной мини-протокол seq + ACK + повторы (окна в 1 достаточно).

Приёмка: при влитых 10% потерь (tc netem или сценарный сброс) файл всё равно передаётся целиком.
ВызовОбнаружение сервисов

Реализуйте multicast/broadcast-обнаружение: клиент вещает DISCOVER, сервер одиночным ответом шлёт свой HTTP-порт.

Приёмка: при нескольких экземплярах клиент перечисляет все без повторов.

Итоги

ТезисВывод
Поверхностьтолько EventDgram; каждая дейтаграмма с адресом источника и флагами
ОтправкаxrtNetUdpSendTo — всё ваше; ответ или форвардинг на любой адрес
Лимитыrecv_limit ≤65535; флаг TRUNCATED обязателен к проверке
ПлатформаICMP-сбросы Windows изолированы; надёжность и порядок — ваши
Поколенияlease текущего поколения на каждую дейтаграмму; семантика перезагрузки как у TCP
API, затронутые в главе
Что дальше по xrt
  • справочник xrt · udp — полный набор приёма-отправки дейтаграмм и инструментов адресных семейств