Создание и отправка пакетов данных в C/С++

Вопрос:Скажем, я хочу отправить следующие данные в сокет, используя C или С++, все в одном пакете: Headers ------- Field 1: 2 byte hex Field 2: 2 byte hex Field 3: 4 byte hex Data ---- Field1 : 2 byte hex Field1 : 8 byte hex Каким будет код, похожий на создание и отправку пакета, содержащего

Вопрос:

Скажем, я хочу отправить следующие данные в сокет, используя C или С++, все в одном пакете:

Headers ——- Field 1: 2 byte hex Field 2: 2 byte hex Field 3: 4 byte hex Data —- Field1 : 2 byte hex Field1 : 8 byte hex

Каким будет код, похожий на создание и отправку пакета, содержащего все эти данные?

Лучший ответ:

Предположим, что ваша программа уже организована, чтобы заголовок содержался в одном struct и данных в другом struct. Например, у вас могут быть такие структуры данных:

#include <stdint.h> struct header { uint16_t f1; uint16_t f2; uint32_t f3; }; struct data { uint16_t pf1; uint64_t pf2; };

Позвоните в эту организацию “формат хоста”. Для меня действительно не имеет значения, что такое формат хоста, если это полезно для остальной части вашей программы. Позвоните в формат, который вы передадите в send() вызов “сетевой формат”. (Я выбрал эти имена в соответствии с htons (междугородняя-короткая) и htonl (имена, основанные на сети).

Вот некоторые функции преобразования, которые могут оказаться удобными. Каждый из них преобразует структуры вашего хоста в буфер сетевого формата.

#include <arpa/inet.h> #include <string.h> void htonHeader(struct header h, char buffer[8]) { uint16_t u16; uint32_t u32; u16 = htons(h.f1); memcpy(buffer+0, &u16, 2); u16 = htons(h.f2); memcpy(buffer+2, &u16, 2); u32 = htonl(h.f3); memcpy(buffer+4, &u32, 4); } void htonData(struct data d, char buffer[10]) { uint16_t u16; uint32_t u32; u16 = htons(d.pf1); memcpy(buffer+0, &u16, 2); u32 = htonl(d.pf2>>32); memcpy(buffer+2, &u32, 4); u32 = htonl(d.pf2); memcpy(buffer+6, u32, 4); } void htonHeaderData(struct header h, struct data d, char buffer[18]) { htonHeader(h, buffer+0); htonData(d, buffer+8); }

Чтобы отправить свои данные, сделайте следующее:

… char buffer[18]; htonHeaderData(myPacketHeader, myPacketData, buffer); send(sockfd, buffer, 18, 0); …

Опять же, вам не нужно использовать структуры header и data, которые я определил. Просто используйте то, что требуется вашей программе. Ключ в том, что у вас есть функция преобразования, которая записывает все данные в четко определенных смещениях в четко определенном порядке байтов в буфер и передает этот буфер функции send().

С другой стороны сетевого подключения вам понадобится программа для интерпретации полученных ею данных. С этой стороны вам нужно написать соответствующие функции (ntohHeader и т.д.). Эта функция будет memcpy битов из буфера и в локальную переменную, которая может перейти к ntohs или ntohl. Я оставлю эти функции для вас.

Ответ №1

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

Если бы затем использовать функции send, sendto, sendmsg или write, надеюсь, с большим вниманием к длине буфера и хорошей обработке ошибок/отчетности.

(Или один из Win32 apis для отправки, если это таргетинг на целевые формы.)

Вы найдете хорошее представление обо всем этом в Beej Guide to Network Programming.

В частности, для части упаковки байтов (с учетом конца) просмотрите тему serialization. (Там более подробно в этом разделе, чем то, что вам нужно для простых целых типов данных фиксированного размера.

Ответ №2

Код будет выглядеть по-разному в зависимости от сетевой библиотеки ОС (* nix использует сокеты Berkeley, Windows использует Winsock и т.д.). Однако вы можете создать структуру, содержащую все данные, которые вы хотите отправить в пакете, например,

typedef struct { short field1; short field2; int field3; } HeaderStruct; typedef struct { short field1; long long field2; } PacketDataStruct;

предполагая 32-разрядный размер int.

Edit:

Как кто-то любезно напомнил мне в комментариях, не забывайте о преобразовании в Network Order. Библиотеки сети будут иметь функции для этого, такие как ntohs, nothl, htons и htonl.

Ответ №3

Один простой ответ заключается в том, что он будет отправлен в формате, который ожидает получатель. Тем не менее, это вызывает вопрос. Предполагая, что данные являются фиксированным размером, как показано, и ожидающая сторона ожидает, вы можете использовать структуру упакованного (1 байт) и хранить данные в каждом поле. Причина использования 1-байтового выравнивания состоит в том, что обычно проще убедиться, что оба конца ожидают одни и те же данные. Без выравнивания по 1 байту структура, возможно, будет выглядеть по-разному в зависимости от параметров компилятора, 32-разрядной и 64-битной архитектуры и т.д.). И, как правило, ожидается, что вы отправите значения в порядке сетевого байта, если шестнадцатеричные значения являются целыми числами. Вы можете использовать такие функции, как htons и htonl (и, возможно, htobe64, если они доступны) для их преобразования.

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

ret = send( socket, &mystruct, sizeof( mystruct ), 0 );

Предполагается, что mystruct объявляется как экземпляр структуры, а не указатель на структуру.

Оцените статью
Добавить комментарий