Сериализация/Десериализация структуры к символу* в C

Так, если я загружаюсь, говорят 20 МБ от MySQL, в Диспетчере задач, RAM для приложения повышается приблизительно на 25 МБ. Тогда, когда я закрываю соединение и пытаюсь расположить ByteArray, RAM никогда не освобождает. Однако, если я использую System.totalMemory, Flash player показывает, что память освобождается, который не имеет место.

Flash player делает что-то как Java и резервирует пространство "кучи" и не выпускает его до выходов приложения?

Хорошо да и не, поскольку Вы, возможно, читали из бесчисленных сообщений в блоге, GC в AVM2 оптимистичен и будет работать свои собственные таинственные пути. Таким образом, это действительно работает немного как Java и попытки зарезервировать пространство "кучи", однако если Вы будете позволять ему достаточно долго и начинать делать другие операции, которые используют некоторую значительную память, то это освободит то предыдущее пространство. Вы видите это использование профилировщика за ночь с некоторыми тестами, работающими сверху Вашего приложения.

5
задан Amro 31 October 2009 в 07:22
поделиться

7 ответов

, поскольку он должен быть отправлен по сети, я настоятельно рекомендую вам преобразовать эти данные в сетевой байт. порядок перед передачей и обратно в порядок байтов хоста при получении. это связано с тем, что порядок байтов не везде одинаков, и, если ваши байты не в правильном порядке, их может стать очень трудно изменить (в зависимости от языка программирования, используемого на принимающей стороне). Функции упорядочения байтов определяются вместе с сокетами и называются htons () , htonl () , ntohs () и ntohl () . (в этом имени: h означает «хост» или ваш компьютер, n означает «сеть», s означает «короткое» или 16-битное значение, l означает «длинное» или 32-битное значение).

тогда вы сами по себе с сериализация, C и C ++ не имеют автоматического способа выполнить это. некоторые программы могут сгенерировать код, который сделает это за вас, например, реализация ASN.1 asn1c, но их сложно использовать, потому что они включают гораздо больше, чем просто копирование данных по сети.

6
ответ дан 18 December 2019 в 14:48
поделиться

У вас может быть класс, представляющий объект, который вы используете в своем программном обеспечении, со всеми тонкостями, функциями членов и всем, что вам нужно. Затем у вас есть «сериализованная» структура, которая больше описывает то, что в конечном итоге окажется в сети.

Чтобы компилятор выполнял все, что вы ему приказываете, вам нужно проинструктировать его «упаковать» структуру. Директива, которую я использовал здесь, предназначена для 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);
}
3
ответ дан 18 December 2019 в 14:48
поделиться

В зависимости от того, достаточно ли у вас места или нет ... вы можете просто использовать потоки :)

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, что обычно дает некоторое пространство.

3
ответ дан 18 December 2019 в 14:48
поделиться
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);

РЕДАКТИРОВАТЬ: исправлен код написанный в ступоре. Кроме того, как отмечено в комментарии, любой такой пакет не является переносимым из-за различий в порядке байтов.

1
ответ дан 18 December 2019 в 14:48
поделиться

Чтобы ответить на ваш вопрос в целом, 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));
0
ответ дан 18 December 2019 в 14:48
поделиться

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

http://code.google.com/apis/protocolbuffers/

0
ответ дан 18 December 2019 в 14:48
поделиться

Как упоминалось в других сообщениях, senderId и sequenceNumber имеют тип int , который, вероятно, будет больше, чем char, поэтому эти значения будут усечены.

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

Например, предположим, что 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;
0
ответ дан 18 December 2019 в 14:48
поделиться