Запишите некоторые данные в Char

еще некоторые проблемы с сетью. Я наткнулся на этот вопрос: Сериализация/десериализация структуры к char* в C, и многие ответы имеют смысл, но я снова и снова вижу это поле «данные char», которое, кажется, несут все пакеты.

Теперь я знаю, для чего это нужно — здесь вы храните данные, которые хотите отправить. Но как на самом деле записать в него данные? Есть ли способы просто хранить целые объекты в этом поле данных? Или мне как-то сериализовать объект, сохранить его в данных, а затем сериализовать пакет, прежде чем я все отправлю?


person Prodigga    schedule 16.02.2012    source источник


Ответы (1)


Каждая переменная существует в памяти вашего компьютера. Память организована в байтах.

Когда вы пишете код C++, вы можете напрямую читать эти байты. Для структуры память для всех ее элементов находится в одном непрерывном блоке (хотя между каждым элементом могут быть промежутки).

Итак, если я объявлю:

struct foo {
    char x;
    char y;
    short z;
    int q;
};

Затем, когда я создаю struct foo, я получаю в памяти следующий макет (всего 8 байтов в большинстве систем):

 xyzzqqqq

Первый байт — x, второй — y, третий и четвертый вместе — z, а последние четыре — q.

Итак, объект уже "сериализован" - у вас есть куча байтов, которые его представляют. Это все, что вам нужно отправить по сети: информацию, которая представляет структуру данных.

Причина, по которой вы написали бы свой собственный сериализатор, заключается в том, что вы можете захотеть изменить способ чтения или записи объекта (например, что, если бы я добавил поле к struct foo?), потому что вам нужно для связи между машинами, где расположение памяти отличается (какой байт z представляет «самую значащую» часть числа?), или потому что вы хотите сериализовать только часть структуры (что, если бы у нас было пустое пространство между членами ?).

Но, по сути, причина, по которой вы отправляете «char data», заключается в том, что все на вашем компьютере может быть представлено таким образом. Я не буду вдаваться в доказательства Тьюринга о кодировании символов, но это математическая уверенность в том, что любое знание может быть закодировано как последовательность единиц и нулей.

Говоря более конкретно, способ, которым вы помещаете данные в поле «char data» пакета, — это memcpying из того места, где данные в данный момент находятся в буфере. Итак, если бы у меня было char* target, я мог бы записать в него struct foo x таким образом:

memcpy(target, &x, sizeof(struct foo));

Или я мог бы сделать это более тщательно, написав каждое поле:

memcpy(target, &x.x, 1);
memcpy(target+1, &x.y, 1);
memcpy(target+2, &x.z, sizeof(short));
memcpy(target+4, &x.q, sizeof(int));

& — это адрес оператора, если вы еще не знали. Итак, я пишу с адреса каждого члена по некоторому смещению в пределах target и записываю количество байтов, равное длине представления переменной члена.

В принятом ответе на ваш последний вопрос указано, что это чрезмерное упрощение: когда вы отправляете многобайтовое целое число по сети, вам нужно беспокоиться о порядке байтов (порядке байтов). Итак, что вы на самом деле делаете, это:

memcpy(target, &x.x, 1);
memcpy(target+1, &x.y, 1);
*((short*)(target+2)) = htons(x.z);
*((int*)(target+4)) = htonl(x.q);

Это обработает изменение байтов соответствующим образом для преобразования узлового порядка байтов в сетевой порядок байтов. Очевидно, что однобайтовые значения невосприимчивы.

person Borealid    schedule 16.02.2012
comment
Средство записи промежуточного программного обеспечения C++ охватывает описанные здесь области. - person ; 16.02.2012
comment
и «чтение» этих данных, как только я подтвержу их тип, будет заключаться в выполнении memcpy из цели char в (скажем) переменную, которая является типом желаемой структуры/класса? так foo* скопировалX; memcpy(copiedX, &target, sizeof(struct foo)); - person Prodigga; 16.02.2012
comment
Еще один вопрос, скажем, вместо struct 'Foo' я буду хранить строку в буфере. 'memcpy(цель, &somestring, sizeof(string));' точно не получится? Так как строка может быть разного размера. Могу ли я вместо этого сделать sizeof (somestring)? - person Prodigga; 16.02.2012
comment
@Prodigga На ваш первый вопрос будет memcpy(&copiedX, target, sizeof(struct foo));, потому что target уже char*. Во-вторых, вы не храните std::string напрямую. Вместо этого вы сохраняете char*, полученное при вызове c_str(), и используете size() для определения длины. При его восстановлении вы сначала видите, какой длины входящие данные, с помощью strlen (или явно используя поле длины в пакете). - person Borealid; 16.02.2012