当前位置: 首页>数据库>正文

Java protobuf序列化大数据量处理较慢问题 protobuf序列化的原理分析


文章目录

  • protubuf
  • protobuf序列化
  • protobuf的原理
  • 定义message
  • 编译message文件
  • 应用protobuf
  • Message 基本用法
  • Message 嵌套使用


protubuf

protobuf序列化

protobuf是一种比json和xml等序列化工具更加轻量和高效的结构化数据存储格式,性能比json和xml真的强很多,毕竟google出品。

protobuf的原理

Java protobuf序列化大数据量处理较慢问题 protobuf序列化的原理分析,Java protobuf序列化大数据量处理较慢问题 protobuf序列化的原理分析_服务器,第1张

定义message

协议的模板
所有的message必须定义到一个文件中,且文件的后缀名为.proto。例如我们定义的bike.proto文件

  • required:必须填

发送的数据

Java protobuf序列化大数据量处理较慢问题 protobuf序列化的原理分析,Java protobuf序列化大数据量处理较慢问题 protobuf序列化的原理分析_c语言_02,第2张

bike.proto

syntax = "proto2"; // 使用的版本

package tutorial; // 生成一个包把类放进去


// 申请短信请求
message mobile_request
{
    required string mobile = 1; // 按顺序写编号
}

编译message文件

编译语法:protoc -I=$SRC_DIR --cpp_out=$DST_DIR bike.proto

SRC_DIR 表示proto文件所在的目录,cpp_out指定了生成的代码的路径, bike.proto指proto文件名。

第一步:

执行:protoc -I=./ --cpp_out=./ bike.proto 这样在当前目录生成了bike.pb.cc和bike.pb.h两个文件。

Java protobuf序列化大数据量处理较慢问题 protobuf序列化的原理分析,Java protobuf序列化大数据量处理较慢问题 protobuf序列化的原理分析_服务器_03,第3张

应用protobuf

  • 把生成了protocol.pb.cc和protocol.pb.h加入到工程,那么接着就是调用一些API,完成序列化和反序列化。
  • API说明 : API说明
  • 编译生成的c++文件 -lprotobuf(链接库)
g++  -std=c++11   main.cc bike.pb.cc -lprotobuf

Message 基本用法

模拟客户端组包发送后,服务端拆包解析数据

mian.cc

执行结果

Java protobuf序列化大数据量处理较慢问题 protobuf序列化的原理分析,Java protobuf序列化大数据量处理较慢问题 protobuf序列化的原理分析_网络_04,第4张

  • 从结果可以看出,手机号为11位,但是序列化后的数据为13位,则多添加了两位数据,分别是:标识号,字节长度。验证了上方protobuf的原理图。

源码:

#include <iostream>
#include <string>
#include "bike.pb.h"

using namespace std;
using namespace tutorial; // 写上包的名称

int main(void)
{
    std::string data; // 存储序列化的消息

    // 客户端发送请求
    {
        // 客户端发送手机号码
        mobile_request mr;
        mr.set_mobile("18684518289");

        mr.SerializeToString(&data); // 把序列化后的数据放入data中
        cout << "序列化后的数据[" << data.length() << "]: " << data << endl;
  
        cout << "标识号为:" << (int)(*data.c_str()) << endl;
        cout << "字节长度为:" << (int)(*(data.c_str() + 1)) << endl;
        // 客户端发送data  send(sockfd, data.c_str(), data.length());
    }


    cout<<"-------------------------"<<endl;
    // 服务器端接受请求
    {
        // receive(sockfd, data, ...);
        //  服务器解析数据
        mobile_request mr;
        mr.ParseFromString(data);
        cout << "客户端手机号码: " << mr.mobile() << endl;
    }

    return 0;
}

Message 嵌套使用

协议的模板
所有的message必须定义到一个文件中,且文件的后缀名为.proto。例如我们定义的bike.proto文件

  • optional:可选的
  • repeated:可重复的 , 相当于可以一个数组

发送的数据

Java protobuf序列化大数据量处理较慢问题 protobuf序列化的原理分析,Java protobuf序列化大数据量处理较慢问题 protobuf序列化的原理分析_网络_05,第5张

bike.proto

syntax = "proto2"; // 使用的版本

package tutorial; // 生成一个包把类放进去

// 成员变量依次赋值1,2,3,4,5,6,......

// 充值查询响应
message list_account_records_response
{
    required int32   code   = 1;    // 响应代号
    optional string  desc   = 2;    // 验证码
    
    message account_record
    {
        required int32  type      = 1; // 0 : 骑行消费,  1 : 充值, 2 : 退款
        required int32  limit     = 2; // 消费或者充值金额
        required uint64 timestamp = 3; // 记录发生时的时间戳
    }
    // 表示内部有3个可重复记录
    repeated account_record records = 3;
}

main.cc

执行结果

Java protobuf序列化大数据量处理较慢问题 protobuf序列化的原理分析,Java protobuf序列化大数据量处理较慢问题 protobuf序列化的原理分析_网络_06,第6张

模拟客户端组包发送后,服务端拆包解析数据

源码:

#include "bike.pb.h"
#include <string>
#include <iostream>

using namespace std;
using namespace tutorial;

int main(void)
{
    std::string data; // 存储序列化的消息

    // 客户端发送请求
    {
        list_account_records_response larr;
        larr.set_code(200);
        larr.set_desc("ok");

        // 创建五条记录
        for (int i = 0; i < 5; i++)
        {
            // 类型为 list_account_records_response + _ + account_record
            list_account_records_response_account_record *ar = larr.add_records(); // 增加一个account_record对象
            ar->set_type(0);
            ar->set_limit(i * 100);
            ar->set_timestamp(time(NULL));
        }

        printf("client recoreds size : %d\n", larr.records_size());
        larr.SerializeToString(&data);// 组包
        // 客户端发送data  send(sockfd, data.c_str(), data.length());
    }

    // 服务器端接受请求
    {
        //receive(sockfd, data, ...);

        list_account_records_response larr;
        larr.ParseFromString(data);// 拆包

        printf("sever recoreds size : %d\n", larr.records_size());
        printf("code: %d\n", larr.code());
        for (int i = 0; i < larr.records_size(); i++)
        {
            // 这里通过索引拿到每个值
            const list_account_records_response_account_record &ar = larr.records(i);
            printf("limit: %d\n", ar.limit());
        }
    }

    return 0;
}



https://www.xamrdz.com/database/64m1957495.html

相关文章: