Привет, Хабр... Да, я опять забыл как называются местные пользователи (хабаровцы? хабровичане? хабровички?.. :), хотя и читал об этом совсем недавно. Бывает, в любом случае, на этот раз я предлагаю простую и достаточно элегантную идею из сетевого мира. И, прежде чем начнём, я оговорюсь, что язык программирования из прошлой статьи ушёл на покой, уступив место молодым и более перспективным наследникам.

Суть

Открывать сетевой канал между субъектами на сразу определённое количество времени либо пакетов с возможностью продления на указываемое число?

Цитата выше — это моя записка на телефоне, которая описывает основополагающую мысль. Представьте, стандартную ситуацию в данном контексте: клиент отправляет серверу запрос на создание соединения и тот соглашается:

Client: OpenConnection<10 second>
Server: OpenConnection<okey>
Client: OpenConnection<5 packet>
Server: OpenConnection<okey>
Client: OpenConnection<2 hour, 1 packet>
Server: OpenConnection<okey>

Предлагаемые время жизни и количество исходящих пакетов. Всё просто, согласитесь? Также, нужно сразу представить продление подключения:

Client: ExtendConnection<128 minute>
Server: ExtendConnection<okey>
Client: ExtendConnection<18 packet>
Server: ExtendConnection<okey>
Client: ExtendConnection<8 minute, 21 packet>
Server: ExtendConnection<okey>

Поясню, что после завершения обозначенного времени либо при отсутствии его обозначения, вступает в дело счётчик оставшихся пакетов — когда он приравнивается нулю, подключение сразу считается безвозвратно закрытым. Кстати, время отсчитывается от момента отправления пакета-подтверждения у отправителя и от момента получения этого пакета у получателя, а счётчик индивидуален, обозначая входящий лимит-требование на количество. То есть:

Client: OpenConnection<1 packet>
Server: OpenConnection<okey>
Client: DataPacket
// Всё, дальше подключение молча умерло.
Client: OpenConnection<15 minute>
Server: OpenConnection<okey>
// Спустя пятнадцать минут, подключение также молча умрёт.
Client: OpenConnection<15 minute, 1 packet>
Server: OpenConnection<okey>
// Спустя пятнадцать минут, подключение будет жить, ведь есть ещё счётчик.
// Теперь сервер ждёт один пакет от клиента.
Server: ExtendConnection<1 packet>
Client: ExtendConnection<okey>
// А теперь, ещё и клиент ждёт от сервера один пакет.
Client: DataPacket
Server: DataPacket
// Подключение ликвидировано...

Думаю, вы уже заметили, что OpenConnection и ExtendConnection требуют соответствующего пакета-ответа, а DataPacket — нет. Конечно же, может быть не только согласие, но и отказ:

Client: OpenConnection<1000000 day>
Server: OpenConnection<bad, connection lifetime is too long>
// Конец, увы ;)

Сразу тогда сообщу, что есть ещё EndPacket, который нужен лишь формально — чтобы обозначить, что больше пакетов твоя сторона не будет отправлять. Иначе говоря, его использование не обязательно, и он нужен лишь для подобного трюка:

Client: OpenConnection<30 minute>
Server: OpenConnection<okey>, ExtendConnection<1 packet>
Client: ExtendConnection<okey>
// Спустя тридцать минут, когда сервер это обнаружил.
Server: EndPacket
// Подключение считается завершённым с обеих сторон.

Обратите внимание, что отправка пакета после завершения, по той или иной причине (например, из-за разницы во времени жизни подключения у клиента и сервера, так как была задержка между отправкой и получением OpenConnection<okey>), подключения у противоположной стороны является полностью корректным поведением, но тогда этот пакет будет обработан получателем как пакет без подключения. Да, можно просто отправлять пакеты:

Client: DataPacket

Формально, первый пакет подключения (OpenConnection) также отправляется одиночным образом. Предупрежу, что нельзя в подключении открыть подключение.

Ах да, теперь самое важное: как следствие, в протоколе нет разделения на клиент-сервер, только субъективное отправитель-получатель (Sender и Receiver).

Пояснения

Для тех кто назовёт это слишком сложным или потребует код, я предлагаю простой алгоритм:

Receiver: Ожидаем входящих пакетов...
Sender: Отправляет пакет EndPacket получателю.
Receiver: Получет пакет от отправителя.
Receiver: Проверяет есть ли у него запись со связкой IP адрес-порт отправителя.
Receiver: Если нет, то просто обрабатываем одиночный пакет (например, игнорируем все кроме OpenConnection от определённого диапазона адресов), иначе продолжаем:
Receiver: Проверяем timestamp (метку времени; например, 09.10.2025 12:23:56) окончания подключения.
Receiver: Если она равна нулю (условное обозначение отсутствия) или уже была пройдена (например, сейчас 09.10.2025 12:24:06), то удаляем запись и обрабатываем как одиночный пакет, иначе продолжаем:
Receiver: Проверяем входящий счётчик-лимитёр пакетов.
Receiver: Если он равен нулю, то удаляем запись и обрабатываем как одиночный пакет, иначе обрабатываем как пакет из соответствующего подключения.
И, конечно же, небольшой кусочек кода на Си:
// Напиши потом, а то сейчас лень писать эту мелочь :)
// Да и спать пора, имей совесть, Ваня...

P.s. Почему Хабр даёт выбрать лишь C++ как язык кода?..

Безусловно, нужно добавить ещё подобную проверку, но для всех записей подключений, например, в потоке для приёма/отправки пакетов, основном потоке ОС или ещё где-нибудь.

В остальном... Я представляю это как простой идентификатор в виде двухбитного big-endian числа:

  1. 0x00 — EndPacket

  2. 0x01 — DataPacket

  3. 0x10 — OpenConnection

  4. 0x11 — ExtendConnection

Такого же типа пакета, но только у последних двух:

  1. 0x00 — Отказ

  2. 0x01 — Согласие

  3. 0x10 — Зарезервировано

  4. 0x11 — Запрос

И наконец, 32-битным неотрицательным, целым числом обозначающим длину тела-содержимого-нагрузки (body/content/payload) и самим упомянутым. Нет, у EndPacket он также присутствует, но я предлагаю использовать какое-нибудь магическую строку или адрес-порт отправителя/получателя. Эквивалентно у Open- и Extend- Connection пакетов в Согласии, в Отказе — сообщение об ошибке (возможно, с её кодом в начале?) и одним/двумя аргументами в Запросе.

Что же насчёт оставшейся структуры, то во-первых, нужно этот протокол обернуть в IP, а во-вторых, я сам понятия не имею... Вот так как-то. Безответственно, но как есть ;-)

Заключение

Лично я считаю, что этот протокола, даже под другим названием, может стать официальным мировым интернет-стандартом из-за своих локаничности и детерминированности... который сможет в итоговом варианте послужить серьёзной альтернативой существующим TCP, UDP и подобным... Увидим, когда подам соответствующий документ в IETF и пройду через тернии к звёздам (ха-ха :). В любом случае, я ожидаю здесь, к статье на Хабре, комментариев с критикой и предложениями. Спасибо за чтение? Не?

Комментарии (29)


  1. HardlinePeak936 Автор
    09.10.2025 10:12

    Вне хабра проскочил вопрос «передачи параметров времени и лимита пакетов. Где в OpenConnection указываются те самые 10 second?» Я думал, что это и так понятно, но, на всякий случай, поясню тут и пойду спать (:

    <packet id><type id><first arg — time><second arg — count> — всё... А как кодировать? Можете предложить варианты!


  1. kipar
    09.10.2025 10:12

    Он поверх TCP работает? Если нет то как будут разруливаться потери\дублирование\изменение порядка пакетов?


    1. HardlinePeak936 Автор
      09.10.2025 10:12

      Нет, сразу поверх IP. Читайте внимательней :)


      1. kipar
        09.10.2025 10:12

        Я так и предположил, но что тогда по второму вопросу?
        Если открыли соединение на 2 пакета, потом клиент отправил 1 пакет а он пришел на сервер дважды - соединение закроется? А если пакет потерялся - соединение наоборот будет висеть до перезагрузки сервера? Что если потеряется EndPacket\OpenConnection\ExtendConnection - во всех случаях будут либо висящие соединения либо прием пакетов без соединения? Тогда я не понимаю чем это лучше UDP.


        1. HardlinePeak936 Автор
          09.10.2025 10:12

          Потери сугубо приемлемы, что уже упоминалось, а дублирование и, возможно, сохранение порядка можно ввести в протокол. Думаю не будет ничего сложного, если добавить ещё пару простых счётчиков входящих и исходящих пакетов в подключении, а также добавлять текущее значение исходящего в отправляемые пакеты, чтобы на той стороне сверялись и отбрасывали дубли либо ожидали предыдущие. Предугадывая вопрос, безусловно необходимо подумать ещё и над сохранением целостности пакетов.

          P.s. Извиняюсь, я вообще не заметил второй вопрос (вторые сутки на ногах ;).


          1. kipar
            09.10.2025 10:12

            потери DataPacket делают бесполезным открытие соединение на заданное число пакетов, так что можно выкинуть его из протокола и оставить только время.
            Потери EndPacket делают бесполезным этот тип пакетов в принципе. Зачем нужен пакет который ничего не гарантирует?
            Потери OpenConnection\ExtendConnection можно разрулить повторной отправкой по таймауту пока не пришел ответ.
            Но это:

            • надо описать в протоколе (а не описывать только идеальную ситуация когда все пакеты доходят)

            • Раз в N минут будет возникать затык равный таймауту(*2 и больше) при плохом соединении, при этом доставка собственно данных все равно не гарантируется.

            • и нет, передача данных когда каждый DataPacket ждет подтверждения от сервера будет сильно менее эффективна чем в TCP, так что для надёжной передачи эффективнее использовать TCP.

            • кстати, а чему этот самый таймаут равен? захардкожен в реализации? определяется по результатам пинга?


  1. garwall
    09.10.2025 10:12

    Дело осталось за малым - представить, что будет с дропом, джиттер, реордером, изменением источника в сессии, нужна ли абстракция, подобная порту, или хватит только абонента, ну и сущая мелочь, убедить хуавеи и циски, что им это надо/


    1. JBFW
      09.10.2025 10:12

      Ну теоретически, с учётом тенденции к запретам и регулировании по всему миру - софтовый роутер, строящий такую сеть, мог бы быть востребован, а при успехе и железячники подтянутся.

      Если оно того будет стоить - и вот это совсем другой вопрос


  1. Storm54
    09.10.2025 10:12

    Неплохо было бы почитать про особенности работы компьютерных сетей, чтобы такую наивную дичь не постить.

    В текущем виде (особенно с подсчетом пакетов) совершенно непонятно, как протокол должен работать с учетом переотправки потерянных пакетов.

    Также, при таком дизайне можно заддосить сервер, открыв множество соединений на длительное время.


    1. HardlinePeak936 Автор
      09.10.2025 10:12

      Не понимаю, что вам непонятно в переотправке потерянных пакетов: по-умолчанию нет никаких механизмов на этот случай, но если вам необходимо, то можно элементарно присылать DataPacket в ответ, разве нет?

      Что же насчёт ддоса, то он возможен и в TCP, и в UDP, так как решается не на этом уровне и достаточно просто: ты можешь отбраковывать неугодные тебе одиночные пакеты (в том числе, и на открытие соединения). Даже по причине подозрительной активности у отправителя...

      Кстати, а что наивного-то? :)


      1. Storm54
        09.10.2025 10:12

        Поэтому и стоит сначала ознакомиться со спецификацией TCP и понять, какие проблемы этот протокол решает, прежде чем выдумывать свой протокол, который просто не будет работать в реальных условиях.

        В этом и заключается Ваша наивность - эффект Даннинга - Крюгера.


        1. HardlinePeak936 Автор
          09.10.2025 10:12

          Как уже говорил ниже, это лишь сырая и обобщённая идея, которая и нужна для этого — чтобы повысить компетенцию, начать дискуссию и, возможно, получить нечто стоящее. С конкретным эффектом же вы промазали, я вполне себе осознаю свою некомпетентность и довольно поверхностное знание в данной теме... Что скажете? :)


  1. Vindicar
    09.10.2025 10:12

    Не нашел в статье ответа на вопросы:

    1. в каком сценарии использования наличие заранее заданных ограничений по времени/числу пакетов будет полезно?

    2. как планируется выбирать эти ограничения с учётом нестабильной работы сети?


    1. vadimr
      09.10.2025 10:12

      Я тоже не понял главным образом, зачем это нужно. Поддержка таблицы соединений стоит денег, зачем это, если цель – просто передавать пакеты?


      1. HardlinePeak936 Автор
        09.10.2025 10:12

        Насчёт таблицы соединений — осмелюсь заметить, что даже для UDP она поддерживается, просто самими провайдерами и в, так сказать, корыстных целях :)

        Соглашусь, что этот протокол залез ещё и на уровне выше (уровень сессий)... но в данном случае — это достаточно обосновано и просто, идя как лёгкий довесок. Нет/да?


    1. HardlinePeak936 Автор
      09.10.2025 10:12

      Всё достаточно элементарно по вашим вопросам:

      1. В любом. Это как сервисные пакеты для проверки соединения в том же TCP, но ты сразу и чётко знаешь сколько их будет или как долго будет соединение. Можете воспринимать это как контракты, например.

      2. Методом научного тыка?.. Не уверен, честно говоря, всё-таки представлял это как: открыл соединение на N минут (предположим, N=5), через N-1 расширил соединение ещё на N, если необходимо, и так на протяжении всей работы. Можно даже производить простенькие вычисления, чтобы не накапливался остаток.

      Я ответил?


      1. Vindicar
        09.10.2025 10:12

        Не вижу сходства. Сервисные пакеты отправляются строго по мере надобности.

        Ключевой момент именно в этом: на транспортном уровне мы не знаем, что, сколько и как долго собирается передавать приложение. В лучшем случае эта информация будет доступна на уровне протокола самого приложения, подобно Keep-Alive в HTTP. И даже там она передаётся "по факту", без попыток угадать заранее.

        А угадать будет непросто. Сеть подтормаживает, и наша прикидка о длительности сессии оказалась некорректной. Соединение разорвётся, несмотря на работоспособность сети? Пользователю это не понравится.

        Далее, а что подразумевается под пакетом? IP пакет? Тогда сразу встаёт вопрос: как быть с фрагментацией пакетов? Фрагмент считается за пакет? Как быть с повторной отправкой?

        И это все при условии что приложение вообще знает, сколько точно данных и как долго оно будет отправлять. Я вообще навскидку затрудняюсь назвать такой сценарий, кроме разве что передачи файла заранее известного размера. Так это всего один сценарий, из-за чего огород-то городить?

        Конечный итог будет простой: приложение будет брать параметры с бааальшим запасом. И тогда ваш протокол мало чем будет отличаться от того же TCP.


        1. HardlinePeak936 Автор
          09.10.2025 10:12

          Согласен с критикой, всё-таки это сырая и обобщённая идея. На случай незнания как раз и нужен ExtendConnection, в остальном — я подумаю над дополнением статьи.


  1. llllXl
    09.10.2025 10:12

    Как будто бы надёжности в этом протоколе нет, да и подделать пакеты третьей стороной в сессии не представляется сложным. Будущее конечно за оптимизацией, но к сожалению не в мире сетевых технологий)


    1. HardlinePeak936 Автор
      09.10.2025 10:12

      Действительно, насчёт механизмов против подделки не было упомянуто, так как они отсутствуют, но их достаточно просто реализовать (как пример: подписью и её проверкой поверх протокола). Возможно, можно сразу учесть и обозначить этот функционал в протоколе... Но я не совсем уверен, стоит ли.

      А вот оптимизации нужны и будут даже в сетевых технологиях, вопрос в том какие, как и когда. Разве нет? ;)


  1. ArPi
    09.10.2025 10:12

    Забыли упомянуть какой из фатальных недостатков имеющихся протоколов ваш решает.

    Так сказать, сравнительный анализ провести.


    1. HardlinePeak936 Автор
      09.10.2025 10:12

      Фатальных? Скорее всего, никакой. Увы, но это просто нечто вроде оптимизации (приводя аналогию, замена неумелого бумажного самолётика на сделанный более аккуратно и ровно ;)


      1. ArPi
        09.10.2025 10:12

        Я так понимаю старый мем вы не узнали :)

        Я как раз это и имел ввиду - в чем заключается оптимизация? Что в имеющихся протоколах на ваш взгляд сделано более неумело? Вот этого анализа не хватает.


        1. HardlinePeak936 Автор
          09.10.2025 10:12

          Действительно, не слышал о таком меме, но принимаю, это забавно и близко. ;)

          Оптимизация же в упрощении и указании по ожиданиям, неумелость же в достаточно высокой сложности, которую можно избежать... И я подумаю над конкретным анализом и сравнением.


  1. Elaugaste
    09.10.2025 10:12

    Почему то мне кажется что это какое то подражание quick.


    1. HardlinePeak936 Автор
      09.10.2025 10:12

      Думаете? А в чём же?


  1. Nemoumbra
    09.10.2025 10:12

    Статья представляет из себя большой мысленный эксперимент. Надо бы всё-таки чё-нибудь написать. Причём на Си я бы не советовал. Возьмите библиотеку scapy на Питоне, опишите её средствами структуру пакетов, с её помощью сбилдите несколько примеров сессий, сохраните в PCAP. Потом можно будет добавить поддержку в Wireshark через Lua-скрипт, чтобы можно было посмотреть на это в удобной форме.

    К моменту, как всё это сделаете, возможно, у вас появится понимание проблем протокола и, возможно, идеи, как это чинить.


  1. Kin77
    09.10.2025 10:12

    Очень нравится читать подобные неопытные наброски, т.к. я также неопытен и интересно как разбирают в комментариях. Благодарю!


  1. cypa
    09.10.2025 10:12

    и где теоретическое моделирование? статистические оценки на реальных данных несущих сетей? примеры применения полезного где?