protobuf-c使用说明

Simple complete example

A simple file, amessage.proto file following the language guide:

 message AMessage
   {
      required int32 a=1; 
      optional int32 b=2;
   }

Generate .h and .c files from the command-line in your current working directory:

 protoc-c --c_out=. amessage.proto

  

Serialize/pack the AMessage as follows:

#include <stdio.h>
#include <stdlib.h>
#include "amessage.pb-c.h"

int main (int argc, const char * argv[]) 
{
    AMessage msg = AMESSAGE__INIT; // AMessage
    void *buf;                     // Buffer to store serialized data
    unsigned len;                  // Length of serialized data
        
    if (argc != 2 && argc != 3)
    {   // Allow one or two integers
        fprintf(stderr,"usage: amessage a [b]\n");
        return 1;
    }
        
    msg.a = atoi(argv[1]);
    if (argc == 3) { msg.has_b = 1; msg.b = atoi(argv[2]); }
    len = amessage__get_packed_size(&msg);
        
    buf = malloc(len);
    amessage__pack(&msg,buf);
        
    fprintf(stderr,"Writing %d serialized bytes\n",len); // See the length of message
    fwrite(buf,len,1,stdout); // Write to stdout to allow direct command line piping
        
    free(buf); // Free the allocated serialized buffer
    return 0;
}

I left most error handling out for brevity. Notice:

the use of      

  1. the A_MESSAGE__INIT macro to construct the message

  2. the has_b member corresponds to the optional b field -- required fields do not   have a has_ member.

  3. amessage__get_packed_size returns the length   of the packed data.

  4. a_message__pack serializes the      message.

On the other hand, to deserialize/unpack a message, try code like this:

#include <stdio.h>
#include <stdlib.h>
#include "amessage.pb-c.h"
#define MAX_MSG_SIZE 1024

static size_t
read_buffer (unsigned max_length, uint8_t *out)
{
  size_t cur_len = 0;
  uint8_t c;
  while ((nread=fread(out + cur_len, 1, max_length - cur_len, stdin)) != 0)
    {
      cur_len += nread;
      if (cur_len == max_length)
        {
          fprintf(stderr, "max message length exceeded\n");
          exit(1);
        }
    }
  return cur_len;
}


int main (int argc, const char * argv[]) 
{
  AMessage *msg;

  // Read packed message from standard-input.
  uint8_t buf[MAX_MSG_SIZE];
  size_t msg_len = read_buffer (MAX_MSG_SIZE, buf);

  // Unpack the message using protobuf-c.
  msg = amessage__unpack(NULL, msg_len, buf);   
  if (msg == NULL)
    {
      fprintf(stderr, "error unpacking incoming message\n");
      exit(1);
    }

  // display the message's fields.
  printf("Received: a=%d",msg->a);  // required field
  if (msg->has_b)                   // handle optional field
    printf("  b=%d",msg->b);
  printf("\n");

  // Free the unpacked message
  amessage__free_unpacked(msg, NULL);
  return 0;
}

During linking each above program, make sure to include '-lprotobuf-c'

Test by piping one program into the next at command line:

./amessage_serialize 10 2 | ./amessage_deserialize 
Writing: 4 serialized bytes
Received: a=10 b=2

Repeated Fields

Here is a simple file, cmessage.proto file:

message CMessage
{
    repeated int32 c=1;
}

Serialize/pack the CMessage as follows:

#include <stdio.h>
#include <stdlib.h>
#include "cmessage.pb-c.h"

int main (int argc, const char * argv[]) 
{
    CMessage msg = CMESSAGE__INIT;  // CMessage (repeated int32)
    void *buf;                      // Buffer to store serialized data
    unsigned len,i;                 // Length of serialized data
    msg.n_c = argc - 1;                      // Save number of repeated int32
    msg.c = malloc (sizeof (int) * msg.n_c); // Allocate memory to store int32
    for (i = 0; i < msg.n_c; i++)
        msg.c[i] = atoi (argv[i+1]);         // Access msg.c[] as array 
    len = cmessage__get_packed_size (&msg);  // This is calculated packing length
    buf = malloc (len);                      // Allocate required serialized buffer length 
    cmessage__pack (&msg, buf);              // Pack the data

    fprintf(stderr,"Writing %d serialized bytes\n",len); // See the length of message
    fwrite (buf, len, 1, stdout);            // Write to stdout to allow direct command line piping

    free (msg.c); // Free storage for repeated int32             
    free (buf);   // Free serialized buffer
    return 0;
}


I left most error handling out for brevity. Notice:

  1. the use of      the C_MESSAGE__INIT macro to construct the message

  2. the n_XXX      member is generated for a repeated field XXX.

On the other hand, if you want to deserialize/unpack a message, try code like this:

#include <stdio.h>
#include "cmessage.pb-c.h"
#define MAX_MSG_SIZE  4096

int main (int argc, const char * argv[]) 
{
    CMessage *msg;
    uint8_t buf[MAX_MSG_SIZE];
    size_t msg_len = read_buffer (MAX_MSG_SIZE, buf);

    msg = cmessage__unpack (NULL, len, buf); // Deserialize the serialized input
    if (msg == NULL)
    { // Something failed
        fprintf(stderr, "error unpacking incoming message\n");
        return 1;
    }
    
    for (i = 0; i < msg->n_c; i++)
    { // Iterate through all repeated int32
        if (i > 0)
            printf (", ");
        printf ("%d", msg->c[i]);
    }
    printf ("\n");
    
    cmessage__free_unpacked(msg,NULL); // Free the message from unpack()
    return 0;
}

Test by piping one program into the next at command line:

./cmessage_serialize 12 3 4 | ./cmessage_deserialize 
Writing: 6 serialized bytes
12, 3, 4

Constructing Submessages

Here is a simple file, dmessage.proto file:

message Submessage
{
    required int32 value=1;
}

message DMessage
{
    required Submessage a=1;
    optional Submessage b=2;
}

Here DMessage consists of one or two integers (a is one int and required; b is one int and optional).

#include <stdio.h>
#include <stdlib.h>
#include "dmessage.pb-c.h"

int main (int argc, const char * argv[]) 
{
    DMessage msg    = DMESSAGE__INIT;   // DMESSAGE
    Submessage sub1 = SUBMESSAGE__INIT; // SUBMESSAGE A
    Submessage sub2 = SUBMESSAGE__INIT; // SUBMESSAGE B
    void *buf;
    unsigned len;
    
    if (argc != 2 && argc != 3)
    {   // Allow one or two integers
        fprintf(stderr,"usage: dmessage a [b]\n");
        return 1;
    }
    sub1.value = atoi (argv[1]); 
    msg.a = &sub1;               // Point msg.a to sub1 data
    
    // NOTE: has_b is not required like amessage, therefore check for NULL on deserialze
    if (argc == 3) { sub2.value = atoi (argv[2]); msg.b = &sub2; } // Point msg.b to sub2 data
    
    len = dmessage__get_packed_size (&msg); // This is the calculated packing length
    buf = malloc (len);                     // Allocate memory
    dmessage__pack (&msg, buf);             // Pack msg, including submessages

    fprintf(stderr,"Writing %d serialized bytes\n",len); // See the length of message
    fwrite (buf, len, 1, stdout);           // Write to stdout to allow direct command line piping
    
    free(buf); // Free the allocated serialized buffer
    return 0;
}

Notice:

  1. there is no has_ flag for optional      submessages -- if the pointer is non-NULL, then we assume that it is a      value.

On the other hand, if you want to deserialize/unpack a message, try code like this:

#include <stdio.h>
#include "dmessage.pb-c.h"
#define MAX_MSG_SIZE 4096

int main (int argc, const char * argv[]) 
{
    DMessage *msg;         // DMessage using submessages
    Submessage *sub1,*sub2;// Submessages
    char c; int i=0;       // Data holders
    uint8_t buf[MAX_MSG_SIZE]; // Input data container for bytes
    
    while (fread(&c,1,1,stdin) != 0)
    {
        if (i >= MAX_MSG_SIZE)
        {
            fprintf(stderr,"message too long for allocated buffer\n");
            return 1;
        }
        buf[i++] = c;
    }
    
    msg = dmessage__unpack(NULL,i,buf); // Deserialize the serialized input
    if (msg == NULL)
    { // Something failed
        fprintf(stderr,"error unpacking incoming message\n");
        return 1;
    }
    sub1 = msg->a; sub2 = msg->b;
    printf("Received: a=%d",sub1->value);
    if (msg->b != NULL) printf(" b=%d",sub2->value);
    printf("\n");
    
    dmessage__free_unpacked(msg,NULL);
    
    return 0;
}

Test by piping one program into the next at command line:

./dmessage_serialize 4 5 | ./dmessage_deserialize 
Writing: 8 serialized bytes
Received: a=4 b=5
./dmessage_serialize 4 | ./dmessage_deserialize 
Writing: 4 serialized bytes
Received: a=4

Constructing Repeated Submessages

Here is a simple file, emessage.proto file:

message Submessage
{
    required int32 value=1;
}

message EMessage
{
    repeated Submessage a=1;
}

Here DMessage consists of one or two integers (a is one int and required; b is one int and optional).

#include <stdio.h>
#include <stdlib.h>
#include "dmessage.pb-c.h"

int main (int argc, const char * argv[]) 
{
    Submessage **subs;
    void *buf;
    unsigned len;
    subs = malloc (sizeof (Submessage*) * (argc-1));
    for (i = 1; i < argc; i++)
       {
         subs[i-1] = malloc (sizeof (Submessage));
         submessage__init (subs[i-1]);
         subs[i-1]->value = atoi(argv[i]);
      }    
    msg.n_a = argc-1;
    msg.a = subs;
    len = emessage__get_packed_size (&msg); // This is the calculated packing length
    buf = malloc (len);                     // Allocate memory
    emessage__pack (&msg, buf);             // Pack msg, including submessages

    fprintf(stderr,"Writing %d serialized bytes\n",len); // See the length of message
    fwrite (buf, len, 1, stdout);           // Write to stdout to allow direct command line piping
    
    free(buf); // Free the allocated serialized buffer
   for (i = 1; i < argc; i++)
      free (subs[i]);
   free (subs); 
   return 0;
}

Notice that repeated fields create two fields, in this case n_a, the number of submessages, and a the submessages themselves. Also note that ais an array of pointers to messages.

On the other hand, if you want to deserialize/unpack a message, try code like this:

#include <stdio.h>
#include "emessage.pb-c.h"
#define MAX_MSG_SIZE 4096

int main (int argc, const char * argv[]) 
{
    EMessage *msg;
    char c; int i=0;
    uint8_t buf[MAX_MSG_SIZE]; // Input data container for bytes
    
    while (fread(&c,1,1,stdin) != 0)
    {
        if (i >= MAX_MSG_SIZE)
        {
            fprintf(stderr,"message too long for allocated buffer\n");
            return 1;
        }
        buf[i++] = c;
    }
    
    msg = emessage__unpack(NULL,i,buf); // Deserialize the serialized input
    if (msg == NULL)
    {
        fprintf(stderr,"error unpacking incoming message\n");
        return 1;
    }
    for (i = 0; i < msg->n_a; i++)
       printf ("%d\n", msg->a[i]->value);
    
    emessage__free_unpacked(msg,NULL);
    
    return 0;
}


Test by piping one program into the next at command line:

./emessage_serialize 4 5 | ./emessage_deserialize 
Writing: 8 serialized bytes
4
5
./emessage_serialize 4 5 8| ./emessage_deserialize 
4
5
8

你可能感兴趣的:(c,protobuf)