使用c中的nanopb在Protobuf中使用回调用于嵌套和重复的字段



*编辑:更新 *我的消息定义为:

message Repeat {
  int32 inum = 1;
  float fnum = 2;
}
message NotSimpleMessage {
  repeated Repeat repeat = 1;
}

我正在尝试使用回调选项编写解码器和编码器。我认为我的编码工作正常,但是我的解码器失败了。我的代码是:定义:

 typedef struct{
        Repeat rep[MAX_NUMBERS];
        int32_t numbers_count;
    }Messer;
typedef struct{
    Mess mess[MAX_NUMBERS];
    int32_t numbers_count;
}MessList;
void mess_add_number(MessList * list, int32_t inum, float fnum)
{
    if (list->numbers_count < MAX_NUMBERS)
    {
        (list->mess[list->numbers_count]).inumber = inum;
        (list->mess[list->numbers_count]).fnumber = fnum;
        list->numbers_count++;
    }
}
    void messer_add_number(Messer * list, int32_t inum, float fnum)
    {
        if (list->numbers_count < MAX_NUMBERS)
        {
            (list->rep[list->numbers_count]).inum = inum;
            (list->rep[list->numbers_count]).fnum = fnum;
            (list->rep[list->numbers_count]).has_inum = true;
            (list->rep[list->numbers_count]).has_fnum = true;
            list->numbers_count++;
        }
    }

编码器/解码器函数:

bool NestedMessage_encode_numbers(pb_ostream_t *ostream, const pb_field_t *field, void * const *arg)
{
    Messer * source = (Messer*)(*arg);
        int i;
        // encode all numbers
        for ( i = 0; i < source->numbers_count; i++)
        {
            if (!pb_encode_tag_for_field(ostream, field))
            {
                const char * error = PB_GET_ERROR(ostream);
                printf("SimpleMessage_encode_numbers error: %sn", error);
                return false;
            }
            if (!pb_encode_submessage(ostream, Repeat_fields, &(source->rep[i])))
            {
                const char * error = PB_GET_ERROR(ostream);
                printf("SimpleMessage_encode_numbers error: %sn", error);
                return false;
            }
        }
        return true;
c}
bool NestedMessage_decode_numbers(pb_istream_t *istream, const pb_field_t *field, void **arg)
{
    MessList * dest = (MessList*)(*arg);
    Repeat rep;
    // decode single number
    Mess decmess;
    printf("decoding...n");
    if (!pb_decode(istream, Repeat_fields ,&rep))
    {
        const char * error = PB_GET_ERROR(istream);
        printf("decode error: %sn", error);
        return false;
    }
    // add to destination list
    mess_add_number(dest, rep.inum, rep.fnum);
    return true;
}

主要是:

int main(void) {

    uint8_t buffer[128];
    size_t total_bytes_encoded = 0;
    // encoding
    // prepare the actual "variable" array
    Messer actualData = { 0 };
    messer_add_number(&actualData, 123, 1.2);
    messer_add_number(&actualData, 456, 2.3);
    messer_add_number(&actualData, 789, 3.4);
    printf("Size: %dn",actualData.numbers_count);
    printf("data to be encoded: %d - %f, %d-%f, %d-%fn",actualData.rep[0].inum,actualData.rep[0].fnum,
            actualData.rep[1].inum, actualData.rep[1].fnum,
            actualData.rep[2].inum,actualData.rep[2].fnum);
    // prepare the nanopb ENCODING callback
    NotSimpleMessage msg = NotSimpleMessage_init_zero;
    msg.repeat.arg = &actualData;
    msg.repeat.funcs.encode = NestedMessage_encode_numbers;
    // call nanopb
    pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
    if (!pb_encode(&ostream, NotSimpleMessage_fields, &msg))
    {
        const char * error = PB_GET_ERROR(&ostream);
        printf("pb_encode error: %sn", error);
        return EXIT_FAILURE;
    }
    total_bytes_encoded = ostream.bytes_written;
    printf("Encoded size: %dn", total_bytes_encoded);

    // decoding
    // empty array for decoding
    Messer decodedData = { 0 };
    // prepare the nanopb DECODING callback
    NotSimpleMessage msgdec = NotSimpleMessage_init_zero;
    msgdec.repeat.arg = &decodedData;
    msgdec.repeat.funcs.decode = NestedMessage_decode_numbers;
    // call nanopb
    pb_istream_t istream = pb_istream_from_buffer(buffer, total_bytes_encoded);
    if (!pb_decode(&istream, NotSimpleMessage_fields, &msgdec))
    {
        const char * error = PB_GET_ERROR(&istream);
        printf("pb_decode error: %s", error);
        return EXIT_FAILURE;
    }
    printf("Bytes decoded: %dn", total_bytes_encoded - istream.bytes_left);
    printf("decoded data: %d - %f, %d-%f, %d-%fn",decodedData.rep[0].inum,decodedData.rep[0].fnum,
            decodedData.rep[1].inum, decodedData.rep[1].fnum,
            decodedData.rep[2].inum,decodedData.rep[2].fnum);
}

我得到的输出是:

大小:3个要编码的数据:123-1.200000,456-2.300000,789-3.400000 编码大小:29字节解码:1个解码数据:0-0.000000, 0-0.0000,0-0.000000

打印编码的缓冲区:

我尝试了解码器内部的一些不同的结构,但它不起作用。可以肯定的是,这是我缺少的一些愚蠢的小东西,但我对此一无所知。

ah,在回调中编码/解码的订阅中有一个小垃圾。

解码时,pb_decode()的工作正常,因为nanopb已经解析了顺言标签和长度。但是,编码时,需要单独计算消息的长度。因此,您需要在这里使用pb_encode_submessage()代替pb_encode()

        if (!pb_encode_submessage(ostream, Repeat_fields, &(source->rep[i])))
        {
            const char * error = PB_GET_ERROR(ostream);
            printf("SimpleMessage_encode_numbers error: %sn", error);
            return false;
        }

(用于参考,这是示例的相关部分。)

-

关于您的更新,此十六进制文本:

0a07087b15ffffff9affffff99ffffff993f0a0808ffffffc80315333313400a0808ffffff950615ffffff9affffff995940

有些损坏,因为您的打印功能似乎打印了" ffffff9a",而不仅仅是" 9a"。可能是一个签名到未签名的演员表现出意外的行为。但这可以通过简单的搜索来解决。替换,给出:

0a07087b159a99993f0a0808c80315333313400a08089506159a995940

用ProtoC解码:

echo 0a07087b159a99993f0a0808c80315333313400a08089506159a995940 | xxd -r -p | protoc --decode=NotSimpleMessage test.proto

给出:

repeat {
  inum: 123
  fnum: 1.2
}
repeat {
  inum: 456
  fnum: 2.3
}
repeat {
  inum: 789
  fnum: 3.4
}

因此,您的编码现在正常工作。

不确定是什么导致解码结束这么早(只有1个字节读)而没有错误消息。也许尝试通过调试器踏上它,看看发生了什么。原因之一可能是,如果缓冲区中的数据在解码调用之前会以某种方式损坏,但是看不出为什么会发生。

在这些定义中,重复和混乱是什么结构?尝试编译很重要。

最新更新