Protobuf C 语言支持工具包
Google Protocol Buffers ,一个非常高效的数据序列化工具,ava/Python/C++/C#等都是完美支持,可惜了,官方不支持C语言,还好世界强大,有人做了C语言版本:https://github.com/protobuf-c/protobuf-c
关于protobuf,请自行google或百度查询,这里不再啰嗦,进入正题。
1. 第一步:安装Protocol Buffers
https://developers.google.com/protocol-buffers/
很简单,download下来,编译即可;make && make install
2. 第二步:安装protobuf-c
https://github.com/protobuf-c/protobuf-c
也是很简单,download下来,编译即可;make && make install
当你输入 protoc-c 出现以下信息,代表安装成功。
jiekechoo:mqtt_protoc jiekechoo$ protoc-c
Usage: protoc-c [OPTION] PROTO_FILES
Parse PROTO_FILES and generate output based on the options given:
-IPATH, --proto_path=PATH Specify the directory in which to search for
imports. May be specified multiple times;
directories will be searched in order. If not
given, the current working directory is used.
If not found in any of the these directories,
the --descriptor_set_in descriptors will be
checked for required proto file.
--version Show version info and exit.
-h, --help Show this text and exit.
--encode=MESSAGE_TYPE Read a text-format message of the given type
from standard input and write it in binary
to standard output. The message type must
be defined in PROTO_FILES or their imports.
--decode=MESSAGE_TYPE Read a binary message of the given type from
standard input and write it in text format
to standard output. The message type must
be defined in PROTO_FILES or their imports.
--decode_raw Read an arbitrary protocol message from
standard input and write the raw tag/value
pairs in text format to standard output. No
PROTO_FILES should be given when using this
flag.
--descriptor_set_in=FILES Specifies a delimited list of FILES
each containing a FileDescriptorSet (a
protocol buffer defined in descriptor.proto).
The FileDescriptor for each of the PROTO_FILES
provided will be loaded from these
FileDescriptorSets. If a FileDescriptor
appears multiple times, the first occurrence
will be used.
-oFILE, Writes a FileDescriptorSet (a protocol buffer,
--descriptor_set_out=FILE defined in descriptor.proto) containing all of
the input files to FILE.
--include_imports When using --descriptor_set_out, also include
all dependencies of the input files in the
set, so that the set is self-contained.
--include_source_info When using --descriptor_set_out, do not strip
SourceCodeInfo from the FileDescriptorProto.
This results in vastly larger descriptors that
include information about the original
location of each decl in the source file as
well as surrounding comments.
--dependency_out=FILE Write a dependency output file in the format
expected by make. This writes the transitive
set of input file paths to FILE
--error_format=FORMAT Set the format in which to print errors.
FORMAT may be 'gcc' (the default) or 'msvs'
(Microsoft Visual Studio format).
--print_free_field_numbers Print the free field numbers of the messages
defined in the given proto files. Groups share
the same field number space with the parent
message. Extension ranges are counted as
occupied fields numbers.
--c_out=OUT_DIR Generate C/H files.
@<filename> Read options and filenames from file. If a
relative file path is specified, the file
will be searched in the working directory.
The --proto_path option will not affect how
this argument file is searched. Content of
the file will be expanded in the position of
@<filename> as in the argument list. Note
that shell expansion is not applied to the
content of the file (i.e., you cannot use
quotes, wildcards, escapes, commands, etc.).
Each line corresponds to a single argument,
even if it contains spaces.
3. 测试protobuf
转换proto文件为 C 语言库
protoc-c --c_out=. kurapayload.proto
生成protoc文件
-rw-r--r-- 1 jiekechoo staff 14836 8 18 11:36 kurapayload.pb-c.c
-rw-r--r-- 1 jiekechoo staff 6427 8 18 11:36 kurapayload.pb-c.h
-rw-r--r-- 1 jiekechoo staff 1749 8 18 11:17 kurapayload.proto
完成protobuf集成工作
#include <stdio.h>
#include <stdlib.h>
#include "MQTTClient.h"
#include "kurapayload.pb-c.h"
void main()
{
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;
int rc;
MQTTClient_create(&client, ADDRESS, CLIENTID,
MQTTCLIENT_PERSISTENCE_NONE, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.username = "username";
conn_opts.password = "password";
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
{
printf("Failed to connect, return code %d\n", rc);
exit(-1);
}
Kuradatatypes__KuraPayload payload = KURADATATYPES__KURA_PAYLOAD__INIT;
Kuradatatypes__KuraPayload__KuraMetric **metrics;
Kuradatatypes__KuraPayload__KuraPosition position = KURADATATYPES__KURA_PAYLOAD__KURA_POSITION__INIT;
position.latitude = 1.1;
position.longitude = 1.1;
payload.position = &position;
metrics = malloc(sizeof (Kuradatatypes__KuraPayload__KuraMetric) * 2);
int i = 0;
for(i=0;i<2;i++)
{
metrics[i] = malloc (sizeof (Kuradatatypes__KuraPayload__KuraMetric));
kuradatatypes__kura_payload__kura_metric__init(metrics[i]);
metrics[i]->name = (char*)EdcBirthPayloadNames[i];
printf("%s, ", metrics[i]->name);
metrics[i]->type = KURADATATYPES__KURA_PAYLOAD__KURA_METRIC__VALUE_TYPE__STRING;
metrics[i]->string_value = (char*)EdcBirthPayloadValues[i];
printf("%s\r\n", metrics[i]->string_value);
}
payload.n_metric = 2;
payload.metric = metrics;
size_t len = kuradatatypes__kura_payload__get_packed_size(&payload);
void* data = malloc(len);
kuradatatypes__kura_payload__pack(&payload, data);
pubmsg.payload = data;
pubmsg.payloadlen = kuradatatypes__kura_payload__get_packed_size(&payload);
MQTTClient_publishMessage(client, BIRTH_TOPIC, &pubmsg, &token);
}
编译,如果没有出错就上成功。
gcc kurapayload.pb-c.c main.c -lprotobuf-c
4. 注意事项
- 系统要能够使用 malloc 功能,好多地方要用到;
- 结构体初始化 INIT 或 使用 init 函数;
- 数据准备完毕,要 pack 一下,再 packed_size 计算长度,后面该怎么处理都行了;
最终,C 语言版本的 Kura 模拟器成功连接 Kapua。