HuldaGnodim 发表于 2023-2-28 14:24

protobuf是线程安全的吗?

参考场景如下,Message里面有两个字段: name 和 age(均未初始化),两个线程同时分别写入name和age字段

zifa2003293 发表于 2023-2-28 14:28

一个故事

这也是很久之前了,在一直都怀念的读书时代,参与的第一个的项目,其中有一部分网络通信,基于socket编程。网络通讯TCP/IP相当于交通工具,上层应用协议还得自己设计。学过计算机网络这门课的,自然会对所学的知识举一反三。
首先查看一个TCP的协议格式, 采用二进制的表示方式进行数据表示。比如一个端口unsigned short,那么网络传输就是16bits。那么相对于二进制传输的协议,比如一些JSON直接是字符串形式传输的,那么一个端口比如65530,那么在JSON中就要用5个字节去分别表示这个5个字节6,5,5,3,0, 会占用更多的带宽。




那么假设我们需求是传递一个学生信息(这个信息也将作为本文后续的例子),信息描述如下:
//这里故意用的汉语拼音,防止英文单词多重含义
enum XingBie
{
FEMALE,
MALE
};

struct School
{
std::string m_strName; //学校名字
std::string m_Address; //学校地址
};

struct Student
{
std::string   m_strName;   //姓名
unsigned int m_uAge;   //年龄
XingBie      m_eXingbie; //性别
std::vector<School> m_vSchools; //学习过的学校
};先来说说通信协议的定义:

[*]整形: 就采用四个字节
[*]字符串: 方法有多种,假设选择了最后一种。

[*]可以在协议中以\0结尾表示结束,也可以在字符串
[*]以固定长度来表示,比如255
[*]在字符串的表述前面加一个长度,这样也可以用来表示任意长度的,任意字符的字节流

[*]数组: 比如上述的Student就读过多所School,那么可以在数组前面加个数量,然后依次输入School信息
这个是一个刚入行的程序员设计的,结果如下.




接下来就会涉及到一个问题了,那就是序列化和反序列化。

[*]序列化: 内存里面的对象是连续内存的,但是对象管理啊的数据不一定,序列化就是将这些内存的数据表示到连续的内存中。作为客户端,将序列化的内容发送到服务端。
[*]反序列化: 一般来说接受到数据的服务器再将数据反序列化为内存里对象的结构状态,便于我们去操作。
而这些序列化的方法就由上述定义的协议来进行代码编写,反序列化则是一个解析数据的过程,也需要进行代码编写。
写着写着,我们就碰到了一些困难:

[*]代码后续要增加新的类型,得重新在协议中定义
[*]后续传输的数据进行变更,对象的成员和方法,序列化与反序列化代码都得跟着去修改,并且可能存在服务器与客户端不一致的兼容性问题。
后来有一天有个爱钻研技术的同学和我说, “你知道google出了个Protobuf吗?”,于是看了看,这个完美的解决了我们的痛点啊。那么接下来就让我们看一看本文的主人公Protocol Buffers(Protobuf)。
相关视频推荐

高并发之protobuf通信协议设计|序列化|协议粘包丨即时通讯设计丨
高性能服务器通信协议设计之xml-json-protobuf对比分析
LinuxC++后台服务器开发架构师免费学习地址
【文章福利】:小编整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!~点击832218493加入(需要自取)




Protobuf for C++

Protobuf 可以快速的帮你完成以下两件事儿:

[*]编写一个Student.proto文件,去定义你的一个Message
[*]然后根据Student.proto, 用protoc生成相应的语言代码, 比如C++, Golang, Python, C#, Java等等。这样也便于在分布式环境中,多个不同语言的服务之间通过Protobuf去通信。其实除了分布式的网络访问方式,有时候也可以在同一个进程里跨语言调用,比如C#/Python/Golang调用C++的代码,使用了Protobuf也就不用过于关心不同语言之间数据类型兼容的问题,调用的时候只需要传入一个序列化的数据地址和数据大小。
Student.proto

这个文件用来定义我们的数据结构,将上一章的例子使用Protobuf来定义。可以看到如下:

[*]协议采用的是proto3
[*]package ProtoSample 那么就转换为C++的namespace ProtoSample
[*]所有的字段均是singular, 也就是proto2中的optional, 并且注意proto3中也没有required字段了。
syntax = "proto3";

package ProtoSample;

message School {
string name = 1;
string address = 2;
}

enum XingBie {
FEMALE = 0;
MALE = 1;
}

message Student {
string name = 1;
int32 age = 2;
XingBie xingbie = 3;
repeated School schools = 4;
}编译Student.proto

Protobuf使用的流程如下图所示:

[*]先编译Protobuf的源码,参照官方文档即可。以Windows为例(Linux类似),编译后产生protoc.exe和libprotobuf.lib
[*]protoc.exe用于编译Student.proto,将产生两个源码文件Student.pb.h和Student.pb.cc: 这个文件主要就是传输的数据结构的定义,包括设置/获取接口,序列化与反序列化等。
[*]最后就是自己的项目编译,把上面产生的Student.pb.h, Student.pb.cc和libprotobuf.lib都引用在项目中。



简单说下编译Student.proto到C++的源码文件的命令:protoc -I=. --cpp_out=. Student.proto
protobuf的代码使用

我写了个简单示例, 这个示例展示了Protobuf产生的对象的使用:

[*]CreateStudent中直接构造一个对象
[*]SerializeToString序列化
[*]ParseFromString反序列化
[*]在有些系统构成中,可能还需要用到json,也可以直接使用MessageToJsonString将对象序列化为一个json
#include <iostream>
#include <string>
#include <vector>
#include "Student.pb.h"
#include "google/protobuf/util/json_util.h"

// 构造一个学生对象
void CreateStudent(ProtoSample::Student& student)
{
student.set_name(u8"一个程序员的修炼之路");
student.set_age(18);
student.set_xingbie(ProtoSample::XingBie::MALE);
auto pSchool = student.add_schools();
pSchool->set_name(u8"小学");
pSchool->set_address(u8"老地方");

pSchool = student.add_schools();
pSchool->set_name(u8"初中");
pSchool->set_address(u8"新地方");
}

//打印一个学生信息
void PrintStudent(const ProtoSample::Student& student)
{
std::cout << "Student Name: " << student.name() << std::endl
    << "Student Age: " << student.age() << std::endl
    << "Student Xingbie: " << student.xingbie() << std::endl;

for (auto& school : student.schools())
{
    std::cout << "School Name: " << school.name() << std::endl
      << "School Address: " << school.address() << std::endl;
}
}

int main()
{
setlocale(LC_CTYPE, "zh-cn.utf-8");

// 1. 构造一个学生信息
ProtoSample::Student student;
CreateStudent(student);

// 2. 序列化学生信息
std::string strStudentInBytes;
student.SerializeToString(&strStudentInBytes);

// 3. 反序列化学生
ProtoSample::Student studentNew;
studentNew.ParseFromString(strStudentInBytes);
PrintStudent(studentNew);

// 4. 序列化到Json格式
std::string strJson;
google::protobuf::util::MessageToJsonString(studentNew, &strJson);
std::cout << strJson << std::endl;

return 0;
}
proto 2 和 proto 3

proto 1是google从2001年就开始开发内部使用,不过还不够完善,也并没有开源,后来完善后开源了proto 2。
proto 2和proto 3并不是相互兼容的,个人认为proto 3除了支持更多的功能,也更加简明。比如Proto 3废弃了optional, 虽然现在等同于默认的singular,但是在proto2中optional int32 name可以使用has_name()来判断是否具有设置这个值,而在proto3中不可以,并且为默认值0,这个在参考3中有比较详细的讨论。
关于更多的区别可以直接查看 Proto V3:
https://github.com/protocolbuffers/protobuf/releases/tag/v3.0.0
这里我们关心一个问题,如果是一个新的项目,该使用Proto 2还是Prot 3。以下是google的官方回答, 一句话建议使用Proto 3。
proto3 is the current version of the language. This is the most commonly used version of the language. We encourage new code to use proto3.

proto2 is an older version of the language. Despite being superseded by proto3, proto2 is still fully supported.Protobuf VS Json

Json也是一个广泛应用于数据传输,那么什么时候用Json什么时候选择Protobuf呢,那就要从他们的特点对比来看一看了。
使用复杂度


相对于而言JSON的使用比较方便:

[*]Protobuf需要定义一个Schema文件.proto,并且需要编译,引入源码文件和库。
[*]JSON直接文本形式表述,很多语言内置支持。
数据表达能力

JSON适合用于表达相对简单的数据结构,而Protobuf直接生成相应语言对应的结构,基本可以表达任意结构,更胜一筹。
数据格式

这个就看使用场景,文本的优势在于可读性好,这样更利于在一些Web调用方面更加合适,便于使用浏览器直接调试。而Protobuf适用于分布式环境中的内部交互,并且一般要求数据表达能力更强,或者使用效率更高的场景。
当然了

[*]JSON采用文本, 一般来说体积比二进制大,传输的带宽和效率也会相对较低。
[*]Protbuf二进制
效率

在序列化,反序列化,一般来说Protobuf效率更高。举个最简单的例子,比如二进制存储(Bytes),在JSON中必然要使用对字节的编码,并且解码,而在Protobuf中直接使用二进制存储。
语言支持

这个必然是Json使用的更加广泛,并且基本语言要么内置JSON解析器,要么就是有很多的SDK。而Protobuf支持的语言数量还是有限。
综合来看,个人的使用意向是,如果Json能够完整表达数据,并且没有太高的效率要求,首选JSON。否则,就选Protobuf吧。

redhat9i 发表于 2023-2-28 14:31

前言
JSON类型数据可读性很好,但是整个数据包中会带有一些无用的数据,会在一定程度上带来通信负担。
本篇文章我们来分享一种更轻量的数据格式——protobuf。
protobuf的优点:

[*]更小、更快、更简单。
[*]支持多种编程语言 。
[*]解析速度快。
[*]可扩展性强。
什么是protobuf、protobuf-c?

Protocol Buffers,是Google公司开发的一种数据格式,类似于XML能够将结构化数据序列化,可用于数据存储、通信协议等方面。它不依赖于语言和平台并且可扩展性极强。
protobuf仓库:
github:https://github.com/protocolbuffers/protobuf
下载速度比较慢,可以先导入到码云,再下载。
protobuf支持多种编程语言:




可以看到,protobuf支持一些主流的语言,唯独没有支持C。所以诞生了第三方的protobuf-c。
protobuf-c仓库:
https://github.com/protobuf-c/protobuf-c
【学习交流群】不知道怎么学?遇到问题没人问?到处找资料?邀请你加入我的嵌入式物联网单片机学习交流群,群内气氛活跃,大咖小白、在职、学生都有,还有群友整理收集的100G教程资料,点击下方进群占位。(点击跳转到群二维码,请放心点击!)

点击进群学习交流docs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRVdocs.qq.com/doc/DUnpkTEdXaExvQlRV

安装protobuf、protobuf-c

我们要使用基于C语言的protobuf,首先需要安装protobuf与protobuf-c。
下面是在Ubuntu下安装的方法:
1、安装protobuf

安装protobuf需要依赖一些工具,需要先安装依赖:
sudo apt-get install autoconf automake libtool curl make g++ unzip
安装完依赖后一依次输入如下命令下载、编译、安装(下载速度慢的话可以先导入码云再下载)protobuf:
git clone https://github.com/protocolbuffers/protobuf.git
cd protobuf
./autogen.sh
./configure
make
sudo make install
sudo ldconfig
其中,执行./autogen.sh命令为了生成configure配置脚本,执行configure可生成Makefile文件,执行make进行编译,执行sudo make install命令进行安装,执行sudo ldconfig命令让动态链接库为系统所共享。
2、安装protobuf-c

同样的,protobuf-c也要依赖于 pkg-config ,输入以下命令进行安装:
sudo apt-get install pkg-config
然后输入如下命令下载、编译、安装protobuf-c:
git clone https://github.com/protobuf-c/protobuf-c.git
cd protobuf-c
./autogen.sh
./configure
make
sudo make install
按以上方式安装的话,protobuf与protobuf-c默认安装在/usr/local路径下:




温馨提示:安装过程可能会出现各种各样的错误,遇到错误的时候仔细看错误描述及看本篇文章安装步骤,看是否遗漏了哪一步。
实践demo

protobuf的核心是一个.proto文件,我们自定义一个.proto来创建我们的协议数据,然后使用protoc-c工具编译生成C代码,有两个文件:一个头文件、一个源文件。
例如我们创建一个student.proto文件:
syntax = "proto2";

message Student
{
    required string name    = 1;
    required uint32 num   = 2;
    required uint32 c_score = 3;
}
其中syntax为语法版本,有proto2、proto3两个版本,我们使用proto2。同C语言类似,.proto也规定了一些数据格式,如proto2的数据类型有:double 、 float、 int32 、 uint32 、 string 等。
本例中,message为关键字,修饰的Student会对应生成我们C中的Student结构体。其中required为前缀修饰,表明该字段是必填字段。还有其它两个修饰关键字:

[*]optional:声明该字段是可选字段。
[*]repeated:声明该字段是可重复字段,通常用数组表示,也可以是list。
使用protoc-c工具工具编译student.proto文件的命令:
protoc --c_out=. student.proto




此时编译会生成student.pb-c.c、student.pb-c.h两个文件。我们看看student.pb-c.h里面有什么:




可以看到,student.pb-c.h里生成了一个协议数据结构体与操作该结构体的一些接口,包括组包与解包接口,对应的student.pb-c.c里就是这些接口对应的实现。
编写我们的student.c测试demo:
左右滑动查看全部代码>>>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "student.pb-c.h"

int main(void)
{
    Student pack_stu = {0};
    uint8_t buffer = {0};
    Student *unpack_stu = NULL;
    size_t len = 0;

    student__init(&pack_stu);

    /* 组包 */
    pack_stu.name = "ZhengN";
    pack_stu.num = 88;
    pack_stu.c_score = 90;
    len = student__pack(&pack_stu, buffer);
    printf("len = %ld\n",len);

    /* 解包 */
    unpack_stu = student__unpack(NULL, len, buffer);
    printf("unpack_stu.name = %s\n", unpack_stu->name);
    printf("unpack_stu.num = %d\n", unpack_stu->num);
    printf("unpack_stu.c_score = %d\n", unpack_stu->c_score);

    student__free_unpacked(unpack_stu, NULL);
    return 0;
}
demo很简单,组包就是构造一个协议数据结构体,调用pack组包接口往buffer中扔数据;解包正好是反过来,从buffer中拿数据放到结构体里。
编译命令:
gcc student.c student.pb-c.c -o student -lprotobuf-c
加上-lprotobuf-c参数链接动态链接库protobuf-c.so,因为前面安装操作的时候有使用ldconfig命令了,所以这里不需要指定动态库路径,否则需要指定.
编译运行:




如果运行时报错:找不到动态库。可输入如下命令导出动态库:
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
以上就是本次关于protobuf的分享,本文给出了pc上的实例,感兴趣的小伙伴不妨尝试运用到stm32、嵌入式Linux中,后续有机会的话再继续做相关分享。
原作者姓名:ZhengNl
原出处:嵌入式大杂烩
原文链接:Protobuf:一种更小、更快、更高效的协议

Doris232 发表于 2023-2-28 14:33

一般的做法是在主线程用mutable_xxx分别拿到两个field的指针,然后把两个指针传给子thread。这样是安全的。
如果每个thread单独用set_ 或者 mutable_ 的话是不安全。

pc8888888 发表于 2023-2-28 14:43

你说的这种情况,protobuf是非安全性的。

JoshWindsor 发表于 2023-2-28 14:47

参考https://developers.google.com/protocol-buffers/docs/reference/cpp/上面的回答,同时写一个mutable object不保证thread safe
页: [1]
查看完整版本: protobuf是线程安全的吗?