2

如何构造具有给定消息规范的请求消息,然后发送到服务器思想 c 套接字?二进制协议用于客户端和服务器通信。以下方法是否正确?

给定消息规范:

字段格式长度值
------------ ------ ------ --------
请求 ID Uint16 2 20
requestNum Uint16 2 100
requestTitle String 10 数据串

    /****************** 方法一 ****************/
    typedef 无符号短 uint16;
    类型定义结构{
        uint16 请求 ID [2];
        uint16 requestNum [2];
        无符号字符请求标题[10];
    }requestMsg;
    …
    请求消息 rqMsg;

    memcpy(rqMsg.requesID, "\x0\x14", 2); //20
    memcpy(rqMsg.requesNum, "\x0\x64", 2); //100
    memcpy(rqMsg.requesTitle, "title01", 10);
    …
    发送(sockfd, &rqMsg, sizeof(rqMsg), 0);

    /******************方法2 ****************/
    无符号字符 rqMsg[14];
    memset(rqMsg, 0, 14);
    memcpy(rqMsg, "\x0\x14", 2);
    memcpy(rqMsg+2, "\x0\x64", 2);
    memcpy(rqMsg+4, "title01", 10);
    …
    发送(袜子,&rqMsg,sizeof(rqMsg),0);
    
4

2 回答 2

3

恐怕你误解了一些东西:长度列似乎告诉你以字节为单位的长度,所以如果你收到一个 uint16 你会收到 2 个字节。

您的第一种方法可能会通过数据结构对齐导致严重的问题。如果我在你的鞋子里,我更喜欢第二种方法,我自己将字节填充到一个字节数组中。

关于在此处填写字段的一般说明:我将 memcpy 用于 uint16 等“本机”字段是没有用的。它可能有效,但只是浪费运行时间。您可以填写结构的字段,只需为其分配一个值,例如rqMsg.requesID = 20;

另一个问题是二进制协议的字节顺序或字节序问题。

作为一个完整的包,我将实现一个“serializeRequest”函数,获取结构的字段并根据协议将其转换为字节数组。

于 2013-01-24T09:50:01.017 回答
0

它们至少部分正确,但我更喜欢第一个,因为与手动索引相比,它允许快速和自然的数据操作和访问,并为错误留下更少的空间。作为奖励,您甚至可以整体复制和分配结构值,并且在 C 中它可以按预期工作。

但是对于任何传出数据,您应该确保使用“打包”结构。它不仅会减少传输到基于数组的实现图的数据量,而且还会确保所有涉及的程序中的字段对齐方式相同。对于我尝试过的大多数 C 编译器(包括 GCC),它可以使用__attribute__((__packed__))属性来完成,但是有不同的编译器需要不同的属性,甚至需要不同的关键字。

如果您的应用程序要在不同的体系结构上运行(ARM 客户端与 x86_64 服务器是一个主要示例),则可能还需要字节序控制。在进行任何计算或数据输出之前,我只是使用一些简单的宏来单独预处理每个字段:

#define BYTE_SWAP16(num)    ( ((num & 0xFF) << 8) | ((num >> 8) & 0xFF) )
#define BYTE_SWAP32(num)    ( ((num>>24)&0xff) | ((num<<8)&0xff0000) | ((num>>8)&0xff00) | ((num<<24)&0xff000000) )

但是您可以使用不同的方法,例如 BCD 编码、单独的解码函数或其他方法。

还要注意 uint16_t 已经是一个 2 字节的值。您可能不需要其中两个来存储您的单个值。

于 2021-02-24T17:50:26.770 回答