Протокол Protocol-Pack: краткое описание
Protocol-Pack (далее PP) — это формат двоичного обмена данными, аналогичный протоколу Google Protocol Buffer (PB). Он использует формат данных TT(L)V (Tag-Type-Length-Value) и обладает характеристиками совместимости как в прямом, так и в обратном направлении. PP предоставляет реализации для нескольких языков: C, C++, Java, Object-C, причём каждая реализация стремится к минималистичному стилю кодирования, простоте, ясности и лёгкости понимания.
PP может использоваться для обмена данными между клиентом и сервером, а также для чтения и записи конфигурационных файлов. Реализации PP на разных языках предоставляют возможность кодировать данные структуры или объекты в строки формата XML. Реализация на C и C++ также предоставляет функции для обработки (или декодирования) данных элементов XML, а чтение XML-конфигурационных файлов может быть реализовано с использованием двух проектов: CXmlLoader и XmlLoader.
Особенности Protocol-Pack
Объяснение путей проекта
Руководство по быстрому старту
Чтобы использовать PP, выполните следующие шаги:
Например, в языке C кодирование структуры Person в двоичные данные осуществляется следующим образом:
PERSON stPerson;
person_field_encode(&stPerson, 1, &stBa); // Второй аргумент 1 указывает на тег Person, третий аргумент stBa хранит массив двоичных данных, его инициализацию и описание смотрите далее в инструкции
Для декодирования структуры Person из двоичных данных в языке C используйте следующий код:
// Предположим, что szBinData содержит двоичные данные для декодирования, а dwDataLen — длину двоичных данных
// Декодирование двоичных данных в структуру Person на языке C выглядит следующим образом:
PERSON stPerson;
memset(&stPerson, sizeof(stPerson), 0);
person_field_decode(&stPerson, szBinData, dwDataLen);
Примечание: языки C, C++ и Java предоставляют класс массива байтов под названием ByteArray, который отвечает за обработку двоичных данных, включая кодирование и декодирование. Инициализация массива байтов на языке C выполняется следующим образом:
char szMsg1[1024]; // Определение размера массива байтов, обратите внимание, что в языке C массив байтов не расширяется автоматически, вы должны выделить достаточно места при инициализации
BYTEARRAY stBa; // Определение массива байтов
INIT_BYTE_ARRAY(stBa, szMsg1, sizeof(szMsg1)); // Инициализация массива байтов
Инициализация массива байтов в языке C++ выполняется следующим образом:
MByteArray stBa; // Массив байтов расширяется автоматически
// Или
MByteArray stBa(1024); // При инициализации указывается начальный размер кэша, если кэш недостаточен, он будет расширен автоматически
// Поскольку при расширении размера массива байтов происходит повторное выделение памяти и копирование данных в новую память, рекомендуется использовать форму с указанием начального размера кэша для избежания частых операций с памятью.
Инициализация массива байтов в Java выполняется следующим образом:
ByteArray ba = new ByteArray(); // Массив байтов расширяется автоматически
// Или
ByteArray ba = new ByteArray(1024); // При инициализации указывается начальный размер кэша, если кэш недостаточен, он будет расширен автоматически
// Поскольку при расширении размера массива байтов происходит повторное выделение памяти и копирование данных в новую память, рекомендуется использовать форму с указанием начального размера кэша для избежания частых операций с памятью.
Демонстрация
Каждая языковая версия предоставляет примеры, расположенные в соответствующих каталогах test. Вот примеры:
Чтобы использовать PP, самое важное — это определить файл описания интерфейса, используя XML для определения структур или объектов. В этой главе мы подробно расскажем, как определить файл описания интерфейса.
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<field-config version="1">
<!-- Здесь определяются макросы, перечисления, структуры и т.д. -->
......
</field-config>
Пример объединения:
<union name='CsRequestData' desc='客户端响应协议消息结构体'> <field name="Login" type="LoginRequest" tag='CS_MSG_LOGIN' desc='客户端登录请求' /> <field name="GetFriends" type="char" tag='CS_MSG_GET_FRIEND_LIST' desc='获取好友列表请求' /> </union>
Если преобразовать в язык C, то соответствующий код будет выглядеть следующим образом:
struct tagCsRequestData { U16 nSelector; // Выборщик объединения, автоматически добавляется генератором кода. union { LOGINREQUEST stLogin; // Клиентский запрос на вход S8 chGetFriends; // Запрос на получение списка друзей }; }; typedef struct tagCsRequestData CSREQUESTDATA; typedef struct tagCsRequestData* LPCSREQUESTDATA;
Здесь выборщик объединения автоматически добавляется генератором кода. Когда его значение совпадает с тегом какого-либо поля в объединении, объединение будет использоваться для сохранения значения этого поля. То есть:
if (nSelector == CS_MSG_LOGIN) { // tagCsRequestData представляет stLogin } else if (nSelector == CS_MSG_GET_FRIEND_LIST) { // tagCsRequestData представляет chGetFriends }
Как и структура, после определения объединение становится новым типом, на который могут ссылаться другие структуры. Его можно сослаться с помощью type или subtype, но необходимо указать атрибут select, пример:
<struct name="CsMsgRequest" version="1" desc="客户端请求协议" > <field name="GID" type="ulong" tag="1" desc="玩家GID" /> <field name="Cmd" type="short" tag="2" desc="消息命令字" /> <field name="ReqData" type="CsRequestData" tag="3" desc="消息结构体" select="Cmd"/> </struct>
Соответствующий код на языке C:
struct tagCsMsgRequest { U64 ullGID; // Игрок GID S16 shCmd; // Команда сообщения CSREQUESTDATA stReqData; // Структура сообщения }; typedef struct tagCsMsgRequest CSMSGREQUEST; typedef struct tagCsMsgRequest* LPCSMSGREQUEST;
В этом примере определена структура CsMsgReuqest, тип подполя ReqData — CsRequestData, это объединение, его селектор указан как Cmd, поэтому когда Cmd==CS_MSG_LOGIN, ReqData будет представлять поле stLogin, а когда Cmd==CS_MSG_GET_FRIEND_LIST, ReqData будет представлять поле chGetFriends.
Генератор кода находится в каталоге CMessage-Creator, это инструмент, написанный на Python, не требующий компиляции и работающий на разных платформах. Для него требуется среда Python версии 2.4 и выше.
Основная программа генератора кода — generator.py, выполнение команды python generator.py --help позволяет просмотреть справку.
Description: генератор сообщений. Version: 1.0.0.0 Usage: python generator.py [-?] [-h] [-s DIRECTORY] [-d DIRECTORY] [-l {c, cpp, java, oc}] [-m FILE_NAME] [-p PACKAGE_NAME] optional arguments: -?, -h, --help Показать эту справочную информацию -s DIRECTORY, --srcpath DIRECTORY Установить каталог поиска файла определения протокола -l {c, cpp, java, oc}, --language {c, cpp, java, oc} Основной язык программирования, который вы хотите использовать, должен быть [c|cpp|java|oc] -d DIRECTORY, --directory DIRECTORY Установите каталог генерации проекта для проекта -m FILE_NAME Задайте имя файла макроса -p PACKAGE_NAME Установите пакет для java Example: python generator.py --help python generator.py -s . -d ../test -l c -m StarMacro
Описание необязательных входных параметров:
Необязательные параметры: -?, -h, --help Отображение справочной информации этой программы -s DIRECTORY, --srcpath DIRECTORY Укажите путь к файлу описания интерфейса -l {c, cpp, java, oc}, --language {c, cpp, java, oc} Язык кода, генерируемого генератором кода, в настоящее время доступны варианты c, cpp, java и oc -d DIRECTORY, --directory DIRECTORY Установка пути генерации кода -m FILE_NAME Установка имени файла определения макроса -p PACKAGE_NAME Установка имени пакета, полезно только для языка java
Однако для данных числового типа (например, 32-битное целое число), их длина фиксирована, и нет необходимости кодировать длину в потоке данных, поэтому формат кодирования для них использует TTV.
PP использует формат TT(L)V для кодирования структуры данных, где: T(Tag): метка поля, используемая для уникальной идентификации или различения поля. При кодировании в двоичном формате занимает 2 байта. T(Type): тип поля, используемый для обозначения типа поля. Занимает 1 байт при кодировании в двоичном виде. L(Length): длина значения поля (Value). Не включает длину, когда тип поля (Type) является целым числом. Занимает 4 байта при кодировании в двоичном виде. V(Value): значение поля. Количество занимаемых байтов определяется параметром L(Length).
Типы полей, поддерживаемые PP:
Тип | Значение Type | Длина в байтах | Описание типа |
char | ``` | | | | | :--: | :--:| :--:| | 1 | 1 | 有符号整数,占1个字节 | | uchar | 2 | 1 | | short | 3 | 2 | | ushort | 4 | 2 | | int | 5 | 4 | | uint | 6 | 4 | | long | 7 | 8 | | ulong | 8 | 8 | | string | 9 | 不固定 | | bytes | 10 | 不固定 | | 结构体类型 | 11 | 不固定 | | array | 12 | 不固定 |
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )