Как стать автором
Поиск
Написать публикацию
Обновить

Каскадный протокол или каскадный баян?

Скажу сразу — не довелось мне изучать сетевые протоколы представительского уровня по каким-либо одобренным программам. Ни школа, ни ВУЗ, нет — только самообучение. Разумеется, кое-что я все же прочитал. Например — статьи в википедии. Тем не менее, ничего подходящего для своих целей я не нашел. И потому пришлось творить…

Интересно посмотреть на ход моих мыслей? Добро пожаловать! Нет? Все равно добро пожаловать!

Если вам не интересен ход моих мыслей, и вы хотите сразу взглянуть на мое чудо — сразу читайте «Знакомьтесь — каскадный протокол».

Предыстория


Все начиналось с малого. Я начал изучать C#. И, надо сказать, мне нравилось.
Моя первая программа была до боли проста — запускала другую программу, предварительно подгрузив html в контрол веб-браузера (ну какое же самообучение могло начаться не с банального «раскидывания» контролов с тулбокса по формам). С тех пор утекло много воды, а мой нынешний pet project исполняет все ту-же функцию — лаунчера к игре. Конечно, теперь все не так просто. Весь проект теперь составляет клиент-серверное приложение, которое умеет регистрировать учетные записи игроков на игровом сервере, просматривать различные статистики, выполнять различные операции с игровыми персонажами, при этом будучи open source, и это только начало… Но речь, как вы поняли, пойдет не об этом.

Начало


Когда я понял, что моему проекту нужно что-то вроде сервера, я был… эээ… «ламером». Но я пытался, думал, и не имея абсолютно никакой теоретической базы — я придумал. Вы будете смеяться. Я и сам сейчас смеюсь. И честно говоря вопрос «А что же в этой конструкции является сервером, а что клиентом?» я бы отнес к категории философских. Суть в том, что мой сервер генерировал файл с необходимой статистикой… и забрасывал на FTP. А клиенты его оттуда забирали. Это конечно было весело, не говоря уже о том, что напрочь отсутствовала обратная связь. Уже потом я начал понимать и читать различные статьи о том, что такое сокеты, и как можно исключить FTP-сервер из моей конструкции.
Что-то мое лирическое отступление затянулось. Перепрыгнем немного вперед, на то время, когда я уже начал задумываться о передачи разнородной информации от сервера клиенту, и вообще организацией полноценного «общения». Наверное это очевидно, что мой следующий шаг — это текстовые команды. В обычный массив байт записывалась строка такого вида:
REG~~~L::loginE::emailP::pass
Структура была проста: 3 буквы, обозначающие команду, 3 символа-разделителя, которые теоретически больше не должны встретиться в теле пакета, и дальше необходимые данные. Начало данных обозначалось буквой и двумя двоеточиями, а конец — либо началом новых данных, либо пустотой (в первых версиях вместо пустоты был END). Стоит ли говорить, что я даже не задумывался над тем, как это будет выглядеть в массиве байт? И вот тут-то и посыпались проблемы. Началось все банально с кодировки — я ведь понятия не имел, что это. Дальше — больше: сложность обработки больших пакетов данных, практически полная невозможность поддержки старой версии протокола после его модификации…
И я начал искать информацию по этому поводу. Особое внимание привлек XML-RPC — удобен и хорошо масштабируется. Но очень громоздкий, зачем мне пересылать текстовые строки, какие-то скобочки и слэши, когда мне нужно передать числовую переменную длиной всего 2 байта? От этого протокола я тоже отказался.

Знакомьтесь — каскадный протокол


В итоге я придумал очень интересный, на мой взгляд, протокол. Может я плохо искал — но аналогов не нашел. Вполне возможно, что я изобрел велосипед, но жалеть даже в таком случае не собираюсь. Полученный опыт очень ценный. Перейдем сразу к делу. Прежде всего хочу сказать, что приведенные ниже примеры подходят только для TCP/IP, так как ответственность за сохранность данных ложится именно на него. Но доработать соответствующее расширение для UDP не составляет труда благодаря каскадности.
Общий вид пакета, запрос:
[заголовок][команда][данные]
Разумеется, на самом деле все без квадратных скобок.
[заголовок] = [размер_команды(4Байт)][размер_данных(8Байт)]
Заголовок всего 12 байт. В качестве команды могут выступать любые данные, я для себя избрал обычные целые положительные числа. Что-то вроде:
001 - установка соединения;
002 - закрытие соединения;
003 - передача файла сервер-клиент;
004 - регистрация;
005 - краткая статистика;
006 - восстановление пароля по email;
007 - перенос персонажа;
008 - запрос значения настройки;
009 - смена email;
010 - авторизация;
011 - повторное письмо активации;

О данных мы поговорим позже. Это и есть самая изюминка — каскадность.
Общий вид пакета, ответ:
[заголовок][ответ][данные]
По аналогии:
[заголовок] = [размер_ответа(4Байт)][размер_данных(8Байт)]
001 - ОК;
002 - ошибка;
003 - возможно обновление клиента;
004 - требуется обновление клиента;
005 - файла не существует;
006 - отключение;

Что же мы можем делать с данными? Например.
Подключение, запрос:
[команда] = 001;
[данные] = [версия_протокола(4Байт)][версия_клиента(4Байт)][размер_публичного_ключа_RSA(4Байт)][публичный_ключ_RSA];

Подключение, ответ:
[ответ] = 001;
[данные(шифровано:RSA)] = [размер_ключа_AES(4Байт)][ключ_AES];
[ответы-альтернатива]: 002, 003, 004;

Вот «рукопожатие» звучит так в моем протоколе. Где-же каскадность? Да, тут она не особо заметна.
Передача файла сервер-клиент, запрос:
[команда] = 003;
[данные] = [размер_имени_файла(4Байт)][смещение_передаваемой_части_файла(4Байт)][имя_файла];

Подключение, ответ:
[ответ] = 001;
[данные] = [размер_передаваемой_части_файла(8Байт)][передаваемая_часть_файла];
[ответы-альтернатива]: 002, 005;

Видите? В этом случае если общий пакет назвать пакетом первого уровня, то секцию [данные] можно назвать пакетом второго уровня, где есть свой заголовок, состоящий из данных фиксированной длины ([размер_имени_файла], [смещение_передаваемой_части_файла]) и, собственно, свои данные ([имя_файла]). Количество уровней ограничено лишь нашей фантазией. Таким образом можно создавать собственные подпротоколы для различных частей нашей программы. Например мою реализацию можно свести к общему виду [заголовок][данные], где данные будут пакетом второго уровня, со своим заголовком (номер запроса/ответа) и своими данными.
Что же мы имеем? Протокол обмена данными. В чем его отличия от остальных? Лично для себя я вижу его преимущества в легком расширении. Добавление новых уровней не изменяет абсолютно ничего в старых. А значит в данном протоколе принцип обратной совместимости реализован на 100%. А еще он довольно «легкий» — заголовки весят минимально (размер сводится к размеру целых чисел, 4 или 8 байт), а разделители отсутствуют напрочь. Ведь намного быстрее начать чтение данных с заданной позиции, чем искать в этих самых данных какую-то метку.

За сим вынужден откланяться — мне еще разрабатывать план по захвату мира выполнять кое-какую работу…
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.