【问题标题】:C - Marshaling/Unmarshaling Struct with htonl and ntohlC - 使用 htonl 和 ntohl 编组/解组结构
【发布时间】:2019-07-23 19:29:33
【问题描述】:

所以我在 c 中有一个结构,我需要通过 UDP 套接字发送它。 RPC 消息应该被展平为一个字节数组,即 message.data。然后 message.data 通过 UDP 套接字发送。

typedef struct {
    enum {Request, Reply} messageType; /* same size as an unsigned int */
    unsigned int RPCId; /* unique identifier */
    unsigned int procedureId; /* e.g.(1,2,3,4) for (+, -, *, /) */
    int arg1; /* argument/return parameter */
    int arg2; /* argument/return parameter */
    /* each int (and unsigned int)is 4
    bytes */
} RPCmessage;

typedef struct {
    unsigned int length;
    unsigned char data[SIZE];
} Message;

我远不精通 c,所以我不知道如何将它展平为一个字节数组以通过套接字发送。我相信我需要使用 htonl() 来编组,并使用 ntohl() 来解组。但我无法让我的 memcpy 表现出我需要的行为。目前我收到警告:从不同大小的整数转换为指针 [-Wint-to-pointer-cast]

void marshal(RPCmessage *rm, Message *message){
    memcpy(&message->data[0], (char *)htonl(rm->messageType), sizeof(rm->messageType));
    memcpy(&message->data[4], (char  *)htonl(rm->RPCId), sizeof(rm->RPCId));

    /* more marshaling follows for the other 4 members */
}

希望它简单吗?但是,当这个问题解决后,我确信将字节数组解组回 RPCmessage 结构时会遇到问题。我的猜测是做这样的事情......但是我不知道如何使用 ntohl 将其恢复到主机订单中。

void unMarshal(RPCmessage *rm, Message *message){
    //here, I am assuming *message is the message received from the socket
    memcpy(rm->messageType, message->data[0], sizeof(rm->messageType));
    memcpy(rm->RPCId, message->data[4], sizeof(rm->RPCId));

    /*more unmarshaling...*/

}

我一直在阅读手册页,但没有点击。目前,指针有点过头了,并试图更好地理解它们。 提前感谢您挽救了我的生命。

【问题讨论】:

  • (char *)htonl(rm->messageType) Nooooo,uint32_t some_temp_var = htonl(rm->messageType) 然后memcpy( .... &some_temp_var, ...)unsigned int 也可能少于 32 位,我建议 uint32_tuint_least32_tunsigned long

标签: c struct marshalling unmarshalling memcpy


【解决方案1】:

htonl 函数返回一个uint32_t 类型的值。它不是一个指针,所以将它转换为一个是没有意义的。这就是警告告诉你的。

您需要将结果存储在临时变量中,然后将临时地址传递给memcpy

uint32_t msgType = htonl(rm->messageType);
uint32_t rpcId = htonl(rm->RPCId);
memcpy(&message->data[0], &msgType, sizeof msgType);
memcpy(&message->data[4], &rpcId, sizeof rpcId);

顺便说一句,对您的数据结构执行适当的编组/解组而不是尝试获取结构的地址来发送/接收它是值得称赞的。

【讨论】:

  • 漂亮!这消除了编译错误,但是 message.data 的每个索引都是一个空字符。
  • @Nate 这是一个不同的问题,需要一个新问题。另外,如果您觉得有用,请随时 accept this answer
  • 一旦整个问题得到解决,我很乐意接受这个答案。由于我有一个空字符串,我无法客观地知道这是正确的答案。我希望这是有道理的。我将发布一个新问题,一旦我看到字符串已填满并且我不必更改您的 memcpy,我保证接受您的回答:)
猜你喜欢
  • 2016-08-23
  • 2014-07-20
  • 1970-01-01
  • 1970-01-01
  • 2017-02-05
  • 2013-03-29
  • 1970-01-01
  • 2012-07-10
  • 1970-01-01
相关资源
最近更新 更多