【ProtoBuf】通讯录实现(网络版)

Protobuf 还常用于通讯协议、服务端数据交换场景。那么在这个示例中,我们将实现一个网络版本的通讯录,模拟实现客户端与服务端的交互,通过 Protobuf 来实现各端之间的协议序列化。

需求如下:

  • 客户端可以选择对通讯录进行以下操作:
  1. 新增⼀个联系人
  2. 删除⼀个联系人
  3. 查询通讯录列表
  4. 查询⼀个联系人的详细信息
  • 服务端提供增、删、查能力,并需要持久化通讯录。
  • 客户端、服务端间的交互数据使用 Protobuf 来完成。

一、环境搭建

Httplib 库:cpp-httplib 是个开源的库,是一个 C++ 封装的 http 库,使用这个库可以在 Linux、Windows 平台下完成 http 客户端、http 服务端的搭建。使用起来非常方便,只需要包含头文件 httplib.h 即可。编译程序时,需要带上 -lpthread 选项。

源码库地址:

yhirose/cpp-httplib: A C++ header-only HTTP/HTTPS server and client library (github.com)


二、Centos 下编写的注意事项

如果使用 CentOS 环境,yum 源带的 g++ 最新版本是 4.8.5,发布于 2015 年,年代久远。编译该项目会出现异常,将 gcc / g++ 升级为更高版本可解决问题。

复制代码
# 安装scl
yum install -y centos-release-scl

# 安装gcc 8版本
yum install -y devtoolset-8-gcc devtoolset-8-gcc-c++

# 启⽤版本
source /opt/rh/devtoolset-8/enable

# 查看版本已经变成gcc 8.3.1
gcc -v

第二步安装 gcc 8 版本的时候,如果显示如下报错:

Could not retrieve mirrorlist http://mirrorlist.centos.org/

可以参考:

SCL更换阿里数据源_centos-sclo-scl-rh.repo-CSDN博客

注意: scl 命令启用只是临时的,退出 shell 或重启就会恢复原系统 gcc 版本,如果要长期使用的话执行:

复制代码
echo "source /opt/rh/devtoolset-8/enable" >> /etc/profile

三、约定双端交互接口

1、新增一个联系人

复制代码
[请求] 
    Post /contacts/add AddContactRequest
    Content-Type: application/protobuf

[响应] 
    AddContactResponse 
    Content-Type: application/protobuf

2、删除一个联系人

复制代码
[请求] 
    Post /contacts/del DelContactRequest 
    Content-Type: application/protobuf

[响应] 
    DelContactResponse 
    Content-Type: application/protobuf

3、查询通讯录列表

复制代码
[请求]
    GET /contacts/find-all 
 
[响应] 
    FindAllContactsResponse 
    Content-Type: application/protobuf

4、查询一个联系人的详细信息

复制代码
[请求] 
    Post /contacts/find-one FindOneContactRequest 
    Content-Type: application/protobuf
 
[响应]
    FindOneContactResponse 
    Content-Type: application/protobuf

四、客户端代码实现

1、add_contact.proto


2、main.cc


3、ContactException.h(定义异常类)


4、makefile


5、运行结果


五、服务端代码实现

1、add_contact.proto(服务端存储通讯录结构定义)


2、main.cc


3、makefile


4、运行结果



六、总结

1、序列化能力对比验证

分别使用 PB 与 JSON 的序列化与反序列化能力, 对值完全相同的一份结构化数据进行不同次数的性能测试。为了可读性,下面这一份文本使用 JSON 格式展示了需要被进行测试的结构化数据内容:

复制代码
{
    "age" : 20,
    "name" : "张珊",
    "phone" : 
    [
        {
            "number" : "110112119",
            "type" : 0
        },
        {
            "number" : "110112119",
            "type" : 0
        },
        {
            "number" : "110112119",
            "type" : 0
        },
        {
            "number" : "110112119",
            "type" : 0
        },
        {
            "number" : "110112119",
            "type" : 0
        }
    ],
    "qq" : "95991122",
    "address" : 
    {
        "home_address" : "陕西省西安市⻓安区",
        "unit_address" : "陕西省西安市雁塔区"
    },
    "remark" : 
    {
        "key1" : "value1",
        "key2" : "value2",
        "key3" : "value3",
        "key4" : "value4",
        "key5" : "value5"
    }
}

开始进行测试代码编写,我们在新的目录下新建 contacts.proto文件,内容如下:

使用 protoc 命令编译文件后,新建性能测试文件 compare.cc,我们分别对相同的结构化数据进行 100、1000、10000、100000 次的序列化与反序列化,分别获取其耗时与序列化后的大小。内容如下:

Makefile:

测试结果如下:


由实验结果可得:

  • 编解码性能:ProtoBuf 的编码解码性能,比 JSON 高出 2-4 倍。
  • 内存占用:ProtoBuf 的内存 278,而 JSON 到达 567,ProtoBuf 的内存占用只有 JSON 的 1/2。
    注意:以上结论的数据只是根据该项实验得出。因为受不同的字段类型、字段个数等影响,测出的数据会有所差异。

该实验有很多可待优化的地方。但其实这种粗略的测试,也能从其中看出 ProtoBuf 的优势。


2、总结

  • XML、JSON、ProtoBuf 都具有数据结构化和数据序列化的能力。
  • XML、JSON 更注重数据结构化,关注可读性和语义表达能力。ProtoBuf 更注重数据序列化,关注效率、空间、速度,可读性差,语义表达能力不足,为保证极致的效率,会舍弃⼀部分元信息。
  • ProtoBuf 的应用场景更为明确,XML、JSON 的应用场景更为丰富。
相关推荐
Hello.Reader1 天前
一文吃透 Protobuf “Editions” 模式从概念、语法到迁移与实战
linux·服务器·网络·protobuf·editions
poemyang3 天前
从JSON到Protobuf,深入序列化方案的选型与原理
rpc·json·protobuf
是店小二呀4 天前
【ProtoBuf 】C++ 网络通讯录开发实战:ProtoBuf 协议设计与 HTTP 服务实现
网络·c++·http·protobuf
poemyang11 天前
RPC的三大问题:跨语言、跨平台通信的终极解决方案是如何炼成的?
网络协议·rpc·序列化
张醒言18 天前
Protocol Buffers 中 optional 关键字的发展史
后端·rpc·protobuf
thginWalker18 天前
第7章 序列化与反序列化:JSON和Protobuf
序列化
lingggggaaaa19 天前
小迪安全v2023学习笔记(六十二讲)—— PHP框架反序列化
笔记·学习·安全·web安全·网络安全·php·反序列化
lingggggaaaa22 天前
小迪安全v2023学习笔记(六十一讲)—— 持续更新中
笔记·学习·安全·web安全·网络安全·反序列化
bkspiderx23 天前
pb2json.hpp 文档:Protobuf 与 JSON 通用转换工具类
json·protobuf·protobuf与json转换
菜菜的后端私房菜1 个月前
Protocol Buffers!高效数据通信协议
java·后端·protobuf