概述
protobuf作为网络通信时的消息载体,不仅效率高,而且还加快开发进度,减少了BUG。
但是protobuf消息生成的类,不管是C++\Java还是其他第三方支持的语言C等生成的消息类,都不太适合用于业务逻辑处理(没有100%的不行,如果非要使用message类作为业务逻辑对象,那么耦合性就太高了)。因此很多时候,我们都需要重复定义至少一份业务逻辑对象,至少是客户端和服务器各一份。那么就涉及到业务逻辑对象和protobuf message之间的互相复制的问题。
1.1 Protobuf使用说明
一个简单的amessage.proto文件如下所示:
message AMessage
{
required int32 a=1;
optional int32 b=2;
oneof test_oneof {
string c=3;
int32 d=4;
}
}
使用如下命令在当前目录下生成protobuf的.c文件和.h文件:
protoc-c --c_out=. amessage.proto
序列化AMessage的代码amessage_serialize.c如下所示:
#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
char *word = "hello world!";
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]); }
msg.c = word;
msg.test_oneof_case = AMESSAGE__TEST_ONEOF_C;
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;
}
注意事项:
l 使用A_MESSAGE__INIT宏来初始化消息结构体
l 成员has_b表示可选成员b是否存在
l 成员test_oneof_case指示oneof使用的成员是哪一个
l AMESSAGE__TEST_ONEOF_C宏表示oneof使用的成员是c
l amessage__get_packed_size函数返回序列化后消息的长度
l amessage__pack函数序列化消息
反序列化消息的代码amessage_deserialize.c如下所示:
#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;
size_t nread;
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);
if (msg->test_oneof_case == AMESSAGE__TEST_ONEOF_C)
printf(" c=%s",msg->c);
else if (msg->test_oneof_case == AMESSAGE__TEST_ONEOF_D)
printf(" d=%d",msg->d);
printf("\n");
// Free the unpacked message
amessage__free_unpacked(msg, NULL);
return 0;
}
通过命令gcc amessage_serialize.c amessage.pb-c.c -o amessage_serialize -I/usr/local/include -I. -L/usr/local/lib -lprotobuf-c和gcc amessage_deserialize.c amessage.pb-c.c -o amessage_deserialize -I/usr/local/include -I. -L/usr/local/lib -lprotobuf-c编译以上代码。
在命令行输入下列命令查看结果
./amessage_serialize 10 2 | ./amessage_deserialize
Writing: 18 serialized bytes
Received: a=10 b=2 c=hello world!