protobuf 序列化 &&协议写入读取io

protobuf是一种比json和xml等序列化工具更加轻量和高效的结构化数据存储格式

官网:https://developers.google.com/protocol-buffers/

protobuf的原理
在这里插入图片描述
API说明 : https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message

使用必须定义协议的模板,最后会翻译成c++的类

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

syntax = "proto2";//用protobuf第几个协议版本

package tutorial;//包  最后生成c++的类

message mobile_request//第一条协议
{
    required string mobile = 1;//等于1是指内部用的编号递增
}

message mobile_response//服务端第一条协议
{
    required int32 code   = 1;   //响应代号
    required int32 icode  = 2;   //验证码
    optional string data  = 3;   //失败原因
}


message login_request//第二条协议
{
    required string mobile  = 1;    // 手机号码
    required int32  icode   = 2;    // 验证码
}


message login_response//服务端第二天协议
{
    required int32   code   = 1;    // 响应代号
    optional string  desc   = 2;    // 验证码
}

message recharge_request//第3条协议
{
    required string mobile  = 1;    // 手机号码
    required int32  amount  = 2;    // 充值金额
}


message recharge_response//服务端第3条协议
{
    required int32   code   = 1;    // 响应代号
    optional string  desc   = 2;    // 验证码
    required int32  balance = 3;    // 最新的余额
}

message account_balance_request//。。。。
{
    required string mobile = 1;
}

message account_balance_response
{
    required int32   code   = 1;    // 响应代号
    optional string  desc   = 2;    // 验证码
    required int32  balance = 3;
}

message list_account_records_request
{
    required string mobile = 1;
}

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; // 记录发生时的时间戳
    }

    repeated account_record records = 3;
}

message list_travel_records_request
{
    required string mobile = 1;
}

message list_travel_records_response
{
    required int32   code   = 1;    // 响应代号
    optional string  desc   = 2;    // 验证码
    message travel_record
    {
        required uint64 stm      = 1;   // start timestamp
        required uint32 duration = 2;   // 骑行时长
        required uint32 amount   = 3;   // 所耗金额
    }

    required double              mileage   = 3; // 里程
    required double              discharge = 4; // 排放
    required double              calorie   = 5; // 卡路里
    repeated travel_record       records   = 6;
}

编译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两个文件
设置这个变量的值就是 前面加set_
取得这条协议的值就是 直接用类名来获得

比如

set_mobile(参数);//设置第一条协议的值
string str =对象名.mobile();//取得这个协议的值 不同的参数用不同的结构来接收

编译生成的c++文件

#include<string>
#include<iostream>

using namespace std;
using namespace tutorial;//当时自定义的包
int main(void)
{
  string data;//最终存储序列化的消息
  //客户端发送的请求
  {
     mobile_request mr;//在bike.pb.h中定义的协议
     mr.set_mobile("18632817488");//客户端的协议设置值
     mr.SerializeToString(&data);//序列化保存到data里
     /**********************************
     **   通过网络把数据data发送出去    **
     **                               **
     **********************************/
   }
  //服务端接收数据 socket 中读取数据后
   {
     mobile_request mr;//在bike.pb.h中定义的协议
     mr.ParseFromString(data);//序列化解析
     cout<<"客户端手机号码"<<mr.mobile()<<endl;
   }

  return 0;
}

g++  -std=c++11   example.cc bike.pb.cc -lprotobuf//example.cc为自己写的源文件包含刚刚生成的头文件  
//最后指定库即可

第二版 嵌套的协议及使用 (list_account_records_response这条协议)

#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++)
        {
			//增加嵌套类  嵌套类前面加add_
            list_account_records_response_account_record * ar = larr.add_records();//嵌套中的类=外围类名+_内类名
            ar->set_type(0);//嵌套类中设置值
            ar->set_limit(i * 100);
            ar->set_timestamp(time(NULL));
        }

        printf("recoreds size : %d\n", larr.records_size());//统计嵌套中有多少个这样的对象
        larr.SerializeToString(&data);//序列化打包
        //客户端发送data  send(sockfd, data.c_str(), data.length());
    }
    //服务器端接受请求
    {
        list_account_records_response larr;
        larr.ParseFromString(data);//序列化解压

        printf("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);//访问这个嵌套的对象 返回的是引用常量需加const
            printf("limit: %d\n", ar.limit());//打印出协议中的消费金额
        }
        
    }

    return 0;
}

附加


    tutorial::mobile_request mr;//协议中的类形
    mr.set_mobile("12345678923");

    int len=mr.ByteSize();//获取这个长度
    memcpy(msg,"FBEB",4);//自定义协议
    *(u16*)(msg+4)=1;
    *(i32)(msg+6)=len;
    mr.SerializeToArray(msg+10,len);//序列化
    mr.ParseFromArray(message, len);//反序列化
    for(int i=0;i<len+10;i++)
	{
	
	printf("%d",msg[i]);
	
	}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity中的protobuf序列化是一种将数据结构转化为字节流的方法,以便在网络传输、存储或在不同平台之间传递数据。它基于Google的protobuf (Protocol Buffers)协议,能够高效地序列化和反序列化复杂的数据结构。 在Unity中使用protobuf序列化需要进行以下几个步骤: 1. 定义消息结构:首先需要在.proto文件中定义要序列化的数据结构。这包括定义消息的字段、枚举、嵌套消息等。可以指定每个字段的类型(整数、浮点数、字符串等)和标签(用于标识字段的唯一性)等信息。 2. 编译.proto文件:使用protobuf编译器将.proto文件编译为相应语言的代码。在Unity中可以使用Protobuf-net等第三方插件来生成C#代码。 3. 序列化数据:在需要序列化数据的地方,将数据按照定义好的消息结构进行赋值,并使用protobuf提供的方法将其序列化为字节流。 4. 反序列化数据:在接收端或需要解析数据的地方,使用protobuf提供的方法将字节流反序列化为消息对象,然后可以通过读取字段的方式获取其中的数据。 使用unity protobuf序列化的好处是: 1. 空间效率高:protobuf采用二进制格式进行序列化,可以将数据压缩为较小的字节流,减少网络传输和存储的空间成本。 2. 速度快:protobuf序列化和反序列化速度较快,可以更有效地处理大量的数据。 3. 跨平台兼容性好:使用protobuf序列化后的数据可以在不同平台、不同语言之间共享和传输,无需担心兼容性问题。 总之,Unity中的protobuf序列化是一种在网络传输和数据存储中高效、方便的数据序列化方法,可以帮助开发者更好地处理数据结构和跨平台数据传输的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值