Передача структуры через Сокеты в C

Короткий ответ: используйте - Вол и позвольте компилятору сделать свое задание.

длинный ответ: эффект другого вида оптимизации невозможно предсказать точно. Иногда оптимизация для быстрого кода на самом деле приведет к меньшему коду, оптимизируя для размера. Если Вы действительно хотите получить последние 0,01% производительности (speedwise или sizewise), необходимо сравнить различной комбинации опций.

кроме того, последние версии Visual Studio имеют опции для более усовершенствованной оптимизации, такой как разовая ссылкой оптимизация и ведомая профилем оптимизация.

48
задан codingfreak 20 October 2009 в 08:19
поделиться

7 ответов

Сериализация - хорошая идея. Вы также можете использовать Wireshark для отслеживания трафика и понимания того, что фактически передается в пакетах.

1
ответ дан 26 November 2019 в 18:45
поделиться

Если вы не хотите писать код сериализации самостоятельно, найдите подходящую структуру сериализации и используйте ее.

Может быть, буферы протокола Google будут возможны?

6
ответ дан 26 November 2019 в 18:45
поделиться

Это очень плохая идея. Двоичные данные всегда должны отправляться таким образом, чтобы:

Don ' никогда не записывать всю структуру двоичным способом, а не в файл или в сокет.

Всегда записывайте каждое поле отдельно и читайте их одинаково.

Вам нужны функции вроде

unsigned char * serialize_int(unsigned char *buffer, int value)
{
  /* Write big-endian int value into buffer; assumes 32-bit int and 8-bit char. */
  buffer[0] = value >> 24;
  buffer[1] = value >> 16;
  buffer[2] = value >> 8;
  buffer[3] = value;
  return buffer + 4;
}

unsigned char * serialize_char(unsigned char *buffer, char value)
{
  buffer[0] = value;
  return buffer + 1;
}

unsigned char * serialize_temp(unsigned char *buffer, struct temp *value)
{
  buffer = serialize_int(buffer, value->a);
  buffer = serialize_char(buffer, value->b);
  return buffer;
}

unsigned char * deserialize_int(unsigned char *buffer, int *value);

Или эквивалентно, конечно, есть несколько способов настроить это в отношении управления буфером и так далее. Затем вам необходимо выполнить высокоуровневые функции, которые сериализуют / десериализуют целые структуры.

Это предполагает, что сериализация выполняется в / из буферов, что означает, что сериализация не выполняется. Не нужно знать, является ли конечным местом назначения файл или сокет. Это также означает, что вы оплачиваете некоторые накладные расходы на память, но, как правило, это хороший дизайн по соображениям производительности (вы не хотите выполнять запись () каждого значения в сокет).

Если у вас есть указанное выше, вот как вы может сериализовать и передать экземпляр структуры:

int send_temp(int socket, const struct sockaddr *dest, socklen_t dlen,
              const struct temp *temp)
{
  unsigned char buffer[32], *ptr;

  ptr = serialize_temp(buffer, temp);
  return sendto(socket, buffer, ptr - buffer, 0, dest, dlen) == ptr - buffer;
}

Несколько замечаний по поводу вышеизложенного:

  • Структура для отправки сначала сериализуется, поле за полем, в буфер .
  • Процедура сериализации возвращает указатель на следующий свободный байт в буфере, который мы используем, чтобы вычислить, сколько байтов он сериализовал в
  • Очевидно, что мои примерные процедуры сериализации не защищают от переполнения буфера.
  • Возвращаемое значение равно 1, если ] sendto () вызов выполнен успешно, иначе будет 0.
72
ответ дан 26 November 2019 в 18:45
поделиться

Использование параметра пакета 'pragma' решило мою проблему, но я не уверен, есть ли у него какие-либо зависимости ??

#pragma pack(1)   // this helps to pack the struct to 5-bytes
struct packet {
int i;
char j;
};
#pragma pack(0)   // turn packing off

Затем следующие строки кода работали все отлично, без проблем

n = sendto(sock,&pkt,sizeof(struct packet),0,&server,length);

n = recvfrom(sock, &pkt, sizeof(struct packet), 0, (struct sockaddr *)&from, &fromlen);
10
ответ дан 26 November 2019 в 18:45
поделиться

There is no need to write own serialisation routines for short and long integer types - use htons()/htonl() POSIX functions.

7
ответ дан 26 November 2019 в 18:45
поделиться

Instead of serialising and depending on 3rd party libraries its easy to come up with a primitive protocol using tag, length and value.

Tag: 32 bit value identifying the field
Length: 32 bit value specifying the length in bytes of the field
Value: the field

Concatenate as required. Use enums for the tags. And use network byte order...

Easy to encode, easy to decode.

Also if you use TCP remember it is a stream of data so if you send e.g. 3 packets you will not necessarily receive 3 packets. They maybe be "merged" into a stream depending on nodelay/nagel algorithm amongst other things and you may get them all in one recv... You need to delimit the data for example using RFC1006.

UDP is easier, you'll receive a distinct packet for each packet sent, but its a lot less secure.

0
ответ дан 26 November 2019 в 18:45
поделиться

Если формат данных, которые вы хотите передать, очень прост, то преобразование в строку ANSI и обратно становится простым и переносимым.

0
ответ дан 26 November 2019 в 18:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: