【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 的应用场景更为丰富。
相关推荐
黑子Kuroko7 天前
【解决方案】微信小程序如何使用 ProtoBuf 进行 WebSocket 通信
前端·websocket·微信小程序·语音识别·protobuf·语音对话·arraybuff
一路向北_.1 个月前
[网鼎杯 2020 青龙组]AreUSerialz
php·反序列化·网鼎杯
bbqz0071 个月前
逆向WeChat(七)
数据库·c++·微信·逆向·protobuf·sqlcipher·破解密钥·解码protobuf·wechatdb
GDAL1 个月前
GeoPB: A Protobuf Solution for Efficient Geospatial Data Handling
javascript·protobuf·geopb
胡耀超1 个月前
序列化与反序列化深入分析:UUID案例的实践与JSON转换对比
java·json·uuid·序列化·反序列化
盒马盒马1 个月前
Protobuf:基本概念与使用流程
google·protobuf
王清欢Randy2 个月前
Apache Arrow IPC 消息格式
数据库·序列化·apache arrow·列存储引擎
A尘埃2 个月前
RPC远程调用的序列化框架
网络·网络协议·rpc·序列化
jackletter2 个月前
c#:System.Text.Json 的使用四(如何忽略[JsonPropertyName])
c#·json·序列化
Lee_SmallNorth2 个月前
@DateTimeFormat和@JsonFormat的区别和使用场景
java·序列化·datetime·localdatetime