Сейчас идёт тестирование: код на GitHub будет открыт после завершения.

Транспортный уровень

ПараметрЗначение
ТранспортTCP (постоянное соединение, persistent)
Порт по умолчанию5225
Опции сокетавключён TCP_NODELAY — небольшие пакеты отправляются немедленно, без задержки Nagle
TLSопционально — если на сервере настроен сертификат, весь поток оборачивается в однонаправленный TLS (аутентификация сервера)
Кодированиебинарные поля фиксированной ширины + ключи в UTF-8. Целые числа — big-endian (сетевой порядок)
Завершение кадраодин байт \n. Обработка \r отсутствует
Пустой кадресли приходит только \n (на месте op стоит \n), он молча игнорируется как keep-alive
Максимальный размер frame192 bytes — включая op, без \n (превышение → E line_too_long, затем соединение закрыто)
Конвейеризацияразрешена — порядок ответов может отличаться от порядка запросов
Таймаут простояотсутствует — сервер не разрывает тихие соединения
Время прогресса frameНе более 5 секунд от первого op-byte до fixed header и LF; частичная отправка не занимает соединение бесконечно

Порядок установления соединения

  1. TCP-подключение
  2. Если на сервере включён TLS — TLS-хендшейк; если подключиться к TLS-серверу в открытом виде, соединение обрывается на этом шаге
  3. Аутентификационный хендшейк — один раз
  4. Далее — обмен кадрами протокола блокировок

Правила фрейминга

Каждое сообщение — это один кадр = одна строка.

[ op:1 байт ][ фиксированный заголовок по op ][ переменное тело ] \n

Принимающая сторона должна сначала определить op, прочитать фиксированный заголовок по числу байт, и только затем сканировать \n. Фиксированный заголовок — это бинарные значения, в которые может попасть байт 0x0A (\n) (например, lease=100A). Сканирование \n применяется только к последнему участку key/текста.

НаправлениеopФиксированный заголовок
клиент → серверA10 bytes (wait:u8 + lease:u8 + owner:u64 BE)
клиент → серверR8 bytes (token:u64 BE)
сервер → клиентA16 bytes (token:u64 BE + owner:u64 BE)
сервер → клиентT · B8 bytes (owner:u64 BE)
сервер → клиентR · N8 bytes (token:u64 BE)
сервер → клиентM · L · E0 bytes (address/reason UTF-8 text)

Если frame больше 192 bytes или malformed, сервер по возможности flush E и закрывает соединение. Клиент также считает malformed, oversized, неизвестный op или некоррелируемый E connection-fatal. Acquire, от которого в этой session отправлен хотя бы один byte, автоматически не повторяется и без окончательного ответа становится Indeterminate.

Термины

  • Кадр (frame) — фрагмент непрерывного потока байтов (TCP), нарезанный на единицы «одно сообщение». В этом протоколе одна строка, заканчивающаяся \n, — это один кадр.
  • Big-endian — порядок записи целых чисел, начиная со старшего байта. Это стандарт сетевых протоколов, поэтому его также называют network order.
  • Конвейеризация (pipelining) — отправка следующего запроса подряд, не дожидаясь ответа на предыдущий. Задержки round-trip перекрываются, что повышает пропускную способность.
  • Keep-alive — бессмысленный сигнал, периодически отправляемый, чтобы показать, что соединение живо. Здесь эту роль играет пустой кадр (\n).