Сервисы UDP: минимальный драйвер мира без соединений
В UDP нет соединений, рукопожатий и порядка — и драйвер XServer соответственно сходится к одному колбэку. Сердцебиения, протоколы обнаружения и сбор логов — его территория.
Обзор
24.1 Введение
Семантика UDP — «каждая дейтаграмма самодостаточна»: ни состояния соединения, ни повторов, ни порядка. Драйвер udp в XServer честно отражает это — bind порта, передача каждой прибывшей дейтаграммы вместе с адресом источника, и всё. Понятие сеанса (если нужно) приложение несёт само в содержимом дейтаграммы.
24.2 Один колбэк
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 покрывает именно это платформенное поведение.
24.5 Контракт
- Заимствование: pMsg (включая Remote/Data) действует в колбэке — перед форвардингом копируйте нужные поля.
- Отправка: всё отправляется самостоятельно через xrtNetUdpSendTo; границы дейтаграмм гарантирует UDP (целостность содержимого проверяете вы).
- Поколения: каждая дейтаграмма берёт lease текущего поколения — при перезагрузке новые идут в новое поколение, семантика как у TCP.
Частые ошибки
- Симптом
- Протокол, рассчитанный на порядок и сеансы, после реальных потерь/переупорядочивания ломает автомат состояний.
- Причина
- UDP не гарантирует ни доставки, ни порядка — сеансы и повторы либо свои (номер последовательности + ACK), либо переходите на TCP.
- Симптом
- Случайная обработка полудейтаграммы; невоспроизводимые ошибки контрольных сумм.
- Причина
- Превышение предела приёма помечается во Flags — без проверки обрывок обрабатывается как целая посылка.
Упражнения
На "PING" отвечать "PONG"; остальное отбрасывать.
Реализуйте прикладной мини-протокол seq + ACK + повторы (окна в 1 достаточно).
Реализуйте multicast/broadcast-обнаружение: клиент вещает DISCOVER, сервер одиночным ответом шлёт свой HTTP-порт.
Итоги
| Тезис | Вывод |
|---|---|
| Поверхность | только EventDgram; каждая дейтаграмма с адресом источника и флагами |
| Отправка | xrtNetUdpSendTo — всё ваше; ответ или форвардинг на любой адрес |
| Лимиты | recv_limit ≤65535; флаг TRUNCATED обязателен к проверке |
| Платформа | ICMP-сбросы Windows изолированы; надёжность и порядок — ваши |
| Поколения | lease текущего поколения на каждую дейтаграмму; семантика перезагрузки как у TCP |
- справочник xrt · udp — полный набор приёма-отправки дейтаграмм и инструментов адресных семейств