Сериализация / десериализация структуры в символ * в C
17054 просмотра
7 ответа
У меня есть структура
struct Packet {
int senderId;
int sequenceNumber;
char data[MaxDataSize];
char* Serialize() {
char *message = new char[MaxMailSize];
message[0] = senderId;
message[1] = sequenceNumber;
for (unsigned i=0;i<MaxDataSize;i++)
message[i+2] = data[i];
return message;
}
void Deserialize(char *message) {
senderId = message[0];
sequenceNumber = message[1];
for (unsigned i=0;i<MaxDataSize;i++)
data[i] = message[i+2];
}
};
Мне нужно преобразовать это в символ *, максимальная длина MaxMailSize> MaxDataSize для отправки по сети, а затем десериализовать его на другом конце
Я не могу использовать TPL или любую другую библиотеку.
Есть ли способ сделать это лучше, мне это не очень удобно, или это лучшее, что мы можем сделать.
Автор: Ankur Chauhan Источник Размещён: 12.11.2019 09:31Ответы (7)
6 плюса
так как это должно быть отправлено по сети, я настоятельно рекомендую вам преобразовать эти данные в порядок байтов сети перед передачей и обратно в порядок байтов хоста при получении. Это связано с тем, что порядок следования байтов не везде одинаков, и, если ваши байты не в правильном порядке, их может быть очень трудно изменить (в зависимости от языка программирования, используемого на принимающей стороне). функции порядка байтов определяются вместе с гнездами, и названы htons()
, htonl()
, ntohs()
и ntohl()
. (в этих именах: h означает «хост» или ваш компьютер, n означает «сеть», s означает «короткое» или 16-битное значение, l означает «длинное» или 32-битное значение).
тогда вы сами по себе с сериализацией, C и C ++ не имеют автоматического способа выполнить это. некоторые программы могут генерировать код, чтобы сделать это для вас, как, например, реализация ASN.1 asn1c, но их сложно использовать, потому что они включают в себя гораздо больше, чем просто копирование данных по сети.
Автор: Adrien Plisson Размещён: 31.10.2009 07:593 плюса
У вас может быть класс, представляющий объект, который вы используете в своем программном обеспечении, со всеми тонкостями и функциями-членами и всем, что вам нужно. Затем у вас есть «сериализованная» структура, которая больше описывает то, что в конечном итоге окажется в сети.
Чтобы убедиться, что компилятор будет делать все, что вы ему скажете, вы должны указать ему «упаковать» структуру. Директива, которую я здесь использовал, предназначена для gcc, смотрите документацию по компилятору, если вы не используете gcc.
Затем подпрограмма сериализации и десериализации просто конвертирует между ними, обеспечивая порядок байтов и подобные детали.
#include <arpa/inet.h> /* ntohl htonl */
#include <string.h> /* memcpy */
class Packet {
int senderId;
int sequenceNumber;
char data[MaxDataSize];
public:
char* Serialize();
void Deserialize(char *message);
};
struct SerializedPacket {
int senderId;
int sequenceNumber;
char data[MaxDataSize];
} __attribute__((packed));
void* Packet::Serialize() {
struct SerializedPacket *s = new SerializedPacket();
s->senderId = htonl(this->senderId);
s->sequenceNumber = htonl(this->sequenceNumber);
memcpy(s->data, this->data, MaxDataSize);
return s;
}
void Packet::Deserialize(void *message) {
struct SerializedPacket *s = (struct SerializedPacket*)message;
this->senderId = ntohl(s->senderId);
this->sequenceNumber = ntohl(s->sequenceNumber);
memcpy(this->data, s->data, MaxDataSize);
}
Автор: 246tNt
Размещён: 31.10.2009 09:17
3 плюса
В зависимости от того, достаточно ли у вас места или нет ... вы можете просто использовать потоки :)
std::string Serialize() {
std::ostringstream out;
char version = '1';
out << version << senderId << '|' << sequenceNumber << '|' << data;
return out.str();
}
void Deserialize(const std::string& iString)
{
std::istringstream in(iString);
char version = 0, check1 = 0, check2 = 0;
in >> version;
switch(version)
{
case '1':
senderId >> check1 >> sequenceNumber >> check2 >> data;
break;
default:
// Handle
}
// You can check here than 'check1' and 'check2' both equal to '|'
}
Я с готовностью признаю, что это занимает больше места ... или что это могло бы.
На самом деле в 32-битной архитектуре int
обычно используется 4 байта (4 символа). Сериализация их с использованием потоков занимает более 4 символов, если значение превышает 9999, что обычно дает некоторое пространство.
Также обратите внимание, что вы, вероятно, должны включить несколько сторожей в ваш поток, просто чтобы проверить, когда вы получите его обратно, что все в порядке.
Версионирование, вероятно, хорошая идея, оно стоит недорого и допускает незапланированную последующую разработку.
Автор: Matthieu M. Размещён: 31.10.2009 04:121 плюс
int senderId;
int sequenceNumber;
...
char *message = new char[MaxMailSize];
message[0] = senderId;
message[1] = sequenceNumber;
Вы переписываете значения здесь. senderId и sequenceNumber являются целыми числами и занимают больше, чем sizeof (char) байтов на большинстве архитектур. Попробуйте что-то вроде этого:
char * message = new char[MaxMailSize];
int offset = 0;
memcpy(message + offset, &senderId, sizeof(senderId));
offset += sizeof(senderId);
memcpy(message + offset, &sequenceNumber, sizeof(sequenceNumber));
offset += sizeof(sequenceNumber);
memcpy(message + offset, data, MaxDataSize);
РЕДАКТИРОВАТЬ: исправлен код, написанный в ступоре. Также, как отмечено в комментарии, любой такой пакет не является переносимым из-за различий в порядке байтов.
Автор: Jherico Размещён: 31.10.2009 07:390 плюса
Чтобы ответить на ваш вопрос в целом, в C ++ нет механизма отражения, поэтому ручная сериализация и десериализация функций, определенных для каждого класса, - лучшее, что вы можете сделать. При этом написанная вами функция сериализации будет искажать ваши данные. Вот правильная реализация:
char * message = new char[MaxMailSize];
int net_senderId = htonl(senderId);
int net_sequenceNumber = htonl(sequenceNumber);
memcpy(message, &net_senderId, sizeof(net_senderId));
memcpy(message + sizeof(net_senderId), &net_sequenceNumber, sizeof(net_sequenceNumber));
Автор: Charles Salvia
Размещён: 31.10.2009 07:50
0 плюса
Как уже упоминалось в других постах, senderId
и sequenceNumber
оба типа int
, которые, вероятно, будет больше , чем полукокса, так будет обрезано эти значения.
Если это приемлемо, то код в порядке. Если нет, то вам нужно разделить их на составляющие их байты. Учитывая, что протокол, который вы используете, будет определять порядок байтов многобайтовых полей, самый переносимый и наименее неоднозначный способ сделать это - сдвиг.
Например, допустим , что senderId
и sequenceNumber
оба 2 байтам, и протокол требует, чтобы старший байт идет первым:
char* Serialize() {
char *message = new char[MaxMailSize];
message[0] = senderId >> 8;
message[1] = senderId;
message[2] = sequenceNumber >> 8;
message[3] = sequenceNumber;
memcpy(&message[4], data, MaxDataSize);
return message;
}
Я бы также рекомендовал заменить for
цикл на memcpy
(если таковой имеется), поскольку он вряд ли будет менее эффективным и сделает код короче.
Наконец, все это предполагает, что char
это один байт. Если это не так, то все данные должны быть замаскированы, например:
message[0] = (senderId >> 8) & 0xFF;
Автор: Steve Melnikoff
Размещён: 31.10.2009 12:27
0 плюса
Вы можете использовать буфер протокола для определения и сериализации структур и классов. Это то, что Google использует внутри, и имеет очень маленький механизм передачи.
http://code.google.com/apis/protocolbuffers/
Автор: Stef Размещён: 31.10.2009 04:39Вопросы из категории :
- c++ What are the barriers to understanding pointers and what can be done to overcome them?
- c++ Какой самый простой способ для анализа файла INI в C ++?
- c++ Когда вы должны использовать «друг» в C ++?
- c++ Как вы очищаете переменную stringstream?
- c++ В C ++ конструктор и деструктор могут быть встроенными функциями?
- c++ Что такое виртуальный базовый класс в C ++?
- c Как вы форматируете unsigned long long int, используя printf?
- c Как реализовать продолжения?
- c Как вы передаете функцию в качестве параметра в C?
- c Как получить список каталогов в C?
- c В чем разница между #include <filename> и #include "filename"?
- serialization Могу ли я сериализовать объект типа C #?
- serialization XmlSerializer - произошла ошибка, отражающая тип
- serialization Самые большие различия между Thrift и Protocol Buffers?
- serialization Как вы делаете глубокую копию объекта в .NET (C # конкретно)?
- serialization Как сериализовать объект в строку
- serialization Сериализация JSON в jQuery