Выравнивание байтов при отправке или получении структуры - PullRequest
0 голосов
/ 10 ноября 2011

Я сталкиваюсь с небольшой проблемой при написании сетевого программного обеспечения.Когда я пытаюсь отправить или получить структуру, которая содержит тип данных 8 байтов, это влияет на следующую отправленную или полученную структуру.Я имею в виду несколько вещей, но сначала я хотел подтвердить одну вещь, прежде чем приступить к отладке.Я использую 32-разрядную версию Ubuntu 11.04 (глупый я) в 64-разрядной системе x-86.Это как-то связано с проблемами выравнивания байтов?

Я разрабатываю контроллер для связи с переключателем Open Flow.Протокол openflow определяет набор спецификаций, основанных на том, какие коммутаторы созданы.Проблема в том, что когда я пытаюсь связаться с коммутатором, все идет хорошо, пока я не отправлю или не получу структуру, которая содержит 64-битный тип даты (uint64_t).Конкретные структуры, которые используются для отправки и получения функций:

estruct ofp_header {
uint8_t version;    /* OFP_VERSION. */
uint8_t type;       /* One of the OFPT_ constants. */
uint16_t length;    /* Length including this ofp_header. */
uint32_t xid;       /* Transaction id associated with this packet.
                       Replies use the same id as was in the request
                       to facilitate pairing. */};   
 assert(sizeof(struct ofp_header) == 8);




/* Switch features. */
struct ofp_switch_features {
struct ofp_header header;
uint64_t datapath_id; /* Datapath unique ID. The lower 48-bits are for a MAC address, while the upper 16-bits are implementer-defined. */
uint32_t n_buffers; /* Max packets buffered at once. */
uint8_t n_tables; /* Number of tables supported by datapath. */
uint8_t pad[3]; /* Align to 64-bits. */

/* Features. */ /* Bitmap of support "ofp_capabilities". */
uint32_t capabilities; /* Bitmap of supported "ofp_action_type"s. */
uint32_t actions; 

/* Port info.*/
struct ofp_phy_port ports[0];  /* Port definitions. The number of ports is inferred from the length field in the header. */
};
assert(sizeof(struct ofp_switch_features) == 32);

Проблема заключается в том, что когда я общаюсь с использованием любых других структур, которые имеют типы данных менее 64-битных, все идет хорошо.Когда я получаю ответ функции, он показывает правильные значения, но после этого, если я получаю любую другую структуру, он показывает значения мусора.Даже если я получаю ответ функции снова, я получаю значения мусора.Короче говоря, если в любой точке кода я получаю запрос функций или любую другую структуру, определенную в спецификациях, которая имеет тип данных 64-битный, следующие структуры получают значения мусора.Код, используемый для отправки и получения запроса функций, выглядит следующим образом:

////// features request and reply  ////////////

ofp_header features_req;

features_req.version=OFP_VERSION;
features_req.type=OFPT_FEATURES_REQUEST;
features_req.length= htons(sizeof features_req);
features_req.xid = htonl(rcv_hello.xid);


if (send(connected, &features_req, sizeof(features_req), 0)==-1) {
printf("Error in sending message\n");
exit(-1);
}
printf("features req sent!\n");



ofp_switch_features features_rep={0};

if (recv(connected, &features_rep, sizeof(features_rep), 0)==-1) {
printf("Error in receiving message\n");
exit(-1);
}

printf("message type : %d\n",features_rep.header.type);
printf("version : %d\n",features_rep.header.version);
printf("message length: %d\n",ntohs(features_rep.header.length));
printf("xid : %d\n",ntohl(features_rep.header.xid));
printf("buffers: %d\n",ntohl(features_rep.n_buffers));
printf("tables: %d\n",features_rep.n_tables);

Ответы [ 5 ]

6 голосов
/ 10 ноября 2011
  1. Перед отправкой преобразуйте свою структуру в массив символов - это вызов сериализация
  2. Используйте семейство функций htons и т. Д., Чтобы гарантировать, что целые числа отправляются в сетевом порядке. Экономит хлопоты на порядках различных машин
  3. Один получающий конец читает байты и восстанавливает структуру.

Это гарантирует, что у вас не возникнет никаких хлопот.

1 голос
/ 11 ноября 2011

Я получил помощь от Daniweb.com, и вся заслуга принадлежит парню с ником NEZACHEM. Его ответ был , и я цитирую:

Проблема не имеет ничего общего с 64-битными типами. Значения, которые вы читаете, не мусор, а очень ценные определения портов:

 struct ofp_phy_port ports[0];  /* Port definitions. The number of ports is inferred from the length field in the header. */

Что означает, как только вы

recv(connected, &features_rep, sizeof(features_rep), 0)

вам нужно проверить features_rep.header.length, выяснить, сколько структур ofp_phy_port следует, выделите для них память и прочитайте эти данные.

Я так и сделал, и благодаря ему мои проблемы были решены, и все прошло хорошо :) Спасибо всем, кто ответил. ура :)

0 голосов
/ 10 ноября 2011

1 В случае, если вы придерживаетесь отправки структур, вы должны убедиться, что они выровнены в байтах.

Для этого используйте прагму pack, например:

#pragma pack(1)
struct mystruct{
  uint8_t  myint8;   
  uint16_t myint16;   
};
#pragma pack()

Делая такВы убедитесь, что эта структура использует только 3 байта.

2 Для преобразования 64-битных значений из порядка хостов в сетевой порядок эта запись читает интересующий: Есть ли какая-либо "стандартная" htonl-подобная функция для 64-битных целых чиселв C ++? (нет, он начинается только с c ++ и заканчивается также C)

0 голосов
/ 10 ноября 2011

Вот что нужно

features_req.version=OFP_VERSION; 
features_req.type=OFPT_FEATURES_REQUEST; 
features_req.length= htons(sizeof features_req); 
features_req.xid = htonl(rcv_hello.xid); 

char data[8];
data[0] = features_req.version;
data[1] = features_req.type;
memcpy(data + 2, &features_req.length, 2);
memcpy(data + 4, &features_req.xid, 4);

if (send(connected, data, 8) ....

На приемном конце

char data[8];

if (recv(conncted, data, 8) ...
features_req.version = data[0];
features_req.type = data[1];
memcpy(&features_req.length, data + 2, 2);
memcpy(&features_req.xid, data + 4, 4);

features_req.length = ntohs(features_req.length);
features_req.xid= ntohl(features_req.xid);
0 голосов
/ 10 ноября 2011

Вы могли бы даже рассмотреть возможность использования сериализации методов: возможно, JSON , XDR , YAML могут быть уместны.или библиотеки типа s11n , jansson и т. д.

...