发送或接收结构时的字节对齐

时间:2011-11-10 17:40:48

标签: c++ c linux sockets network-programming

我在编写网络软件时面临一些问题。当我尝试发送或接收包含8字节数据类型的结构时,下一个发送或接收的结构以某种方式受到影响。我有几点想法,但首先我想在进入调试之前确认一件事。 我在64位x-86系统上使用32位Ubuntu 11.04(愚蠢的我)。这与字节对齐问题有关吗?

我正在开发一个与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 个答案:

答案 0 :(得分:6)

  1. 在发送之前将结构转换为字符数组 - 这是调用序列化
  2. 使用函数族htons等确保以网络顺序发送整数。为各种机器的端部节省麻烦
  3. 一个接收端读取字节并重构结构。
  4. 这将确保您不会有任何麻烦。

答案 1 :(得分:1)

我得到了Daniweb.com的帮助,所有的功劳都归功于一个带有NEZACHEM缺口的人。 His answer was,我引用:

  

该问题与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,   弄清楚p_phy_port的结构有多少,   为他们分配内存并读取这些数据。

我做到了,多亏了他,我的问题得到了解决,一切顺利:) 感谢所有回复的人。 干杯:)

答案 2 :(得分:0)

您甚至可以考虑使用serialization技术:或许JSONXDRYAML可能相关。或s11njansson

等图书馆

答案 3 :(得分:0)

这是想要的东西

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);

答案 4 :(得分:0)

1如果你坚持发送结构,你应该确保它们是字节对齐的。

为此,请使用pragma pack,如下所示:

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

这样做可以确保此结构仅使用3个字节。

2为了将64位值从主机顺序转换为网络顺序,这篇文章读取了解释:Is there any "standard" htonl-like function for 64 bits integers in C++?(不,它只以c ++开头,也以C结尾)