Как десериализовать INT из проводного формата из сокета в C ++ - PullRequest
0 голосов
/ 04 июля 2019

У меня есть сообщение protobuf, которое содержит заголовок и тело. Заголовок имеет член с именем size (отражающий размер всего сообщения, т.е. заголовок плюс тело). Так как protobuf (AFAIK) не предоставляет границы сообщения, я использую размер (первый элемент заголовка и фиксированный размер 4 байта), чтобы узнать, сколько нужно вытянуть из сокета.

Предполагая, что я прочитал (или recv (2) ed) 4 байта из сокета, мне теперь нужно преобразовать (декодировать) это в целое число, чтобы я мог дать команду recv (2) сделать это намного больше.

Как мне преобразовать / декодировать этот проводной формат в int в C ++ land?

Я пробовал ParseFromString (), но эта функция возвращает логическое значение, и документ не говорит мне много.

Я покажу то, что считаю уместным ... посмотрим

message PsdAgentMsg { 
    message Header { 
       fixed32 theSize = 1; // size includes header and message 
       uint32 theInstanceId = 2; 
       Type theMsgType = 3; 
    } 
    Header theHeader = 1;
    oneof theMsg { 
       abc = 2; 
       def = 3; 
       ghi = 4; 
       klm = 5; 
       PsdAgentGPCMsg theGPCMsg = 6; 
    } 
} 
message PsdAgentGPCMsg { 
    int32 theCount = 1; 
} 
...few minutes later..

PsdAgentMsg *msg = new PsdAgentMsg();   // psd msg is header + body
...
rc = recv(sock, buf, 4, 0);     // I am simplifying some stuff
std::string sizeString = buf;
...
size_t payloadSize = msg->ParseFromString(sizeString);

Я обнаружил, что payloadSize = 0. Это ложное присвоение size_t. Поэтому ParseFromString () не является правильным способом декодирования 4-х байтов. Опять же, мне нужно декодировать sizeString в int. так что я могу сказать recv (sock, buf, payloadSize, 0)

1 Ответ

0 голосов
/ 04 июля 2019

Во встроенных полях сообщений используется проводной тип 2: длина ограничена.

Это означает, что кодируется так:

<varint tagAndType> <varint messageLength> <theSize> <theInstanceId> <theMsgType>

Где varint - это вариация base-128, как определено в спецификации кодирования protobuf .


Это означает, что theSize не имеет фиксированного смещения от начала сообщения. Чтобы сделать вещи проще, вы можете отправить общий размер сообщения, прежде чем отправлять само сообщение. то есть, получено сообщение, подобное этому:

message PsdAgentMsg { 
    message Header { 
       uint32 theInstanceId = 2; 
       Type theMsgType = 3; 
    }

    Header theHeader = 1;
    oneof theMsg { 
       int32 abc = 2;
       string def = 3;
       double ghi = 4;
       uint32 klm = 5;
       PsdAgentGPCMsg theGPCMsg = 6; 
    } 
}

Вы можете отправить ваши данные примерно так:

PsdAgentMsg msg;
fillOutMessageFields(msg);

std::string encoded_msg = msg.SerializeAsString();
uint32_t size = msg.size();

// First send the message size as a fixed-size integer
size = htonl(size);
send(sockfd, &size, sizeof(size), 0);

// Then send the message itself
send(sockfd, msg.c_str(), msg.size(), 0);

Тогда вы можете прочитать это на другом конце, как это:

// Read the size
uint32_t size;
rc = recv(sockfd, &size, sizeof(size), 0);
assert(rc == sizeof(size));  // Or proper error handling
size = ntohl(size);

// Read the actual message
std::string encoded_msg(size, '\0');
rc = recv(sockfd, &encoded_msg[0], size, 0);
assert(rc == size);  // Or proper error handling

// Parse the message
PsdAgentMsg msg;
msg.ParseFromString(encoded_msg);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...