共享单车(三):应用层协议设计

protobuf 是一种比 json 和 xml 等序列化工具更加轻量和高效的结构化数据存储格式。
https://developers.google.com/protocol-buffers/

在这里插入图片描述

安装

apt-get install autoconf automake libtool curl make g++ unzip
$ git clone https://github.com/protocolbuffers/protobuf.git 
$ cd protobuf 
$ git submodule update --init --recursive 
$ ./autogen.sh 
$ ./configure 
$ make 
$ make check 
$ sudo make install 
$ sudo ldconfig 

遇到问题:

sudo chmod +777 -R protobuf-3.19.4

在这里插入图片描述

在这里插入图片描述

需求设计

1.定义proto文件

syntax = "proto2";

package tutorial;

message mobile_request
{
    required string mobile = 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
{
    required string mobile  = 1;    // 手机号码
    required int32  amount  = 2;    // 充值金额
}


message recharge_response
{
    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;
}

package:为.proto文件添加package声明符,可以防止不同 .proto项目间消息类型的命名发生冲突。
protobuf 包类型的解析和C++类似,都是由内而外进行解析。对于C++,产生的类会被包装在C++的命名空间中(tutorial)

option:会影响特定环境下的处理方式,但是不会改变整个文件声明的含义。

message:消息体,包含了多个fields(数据项),每一个fields都是key-value类型。message经过protoc编译后会生成对应的class类,field则会生成对应的方法。

2.protoc编译器

使用proto文件定义好结构数据后,可以使用protoc编译器生成结构数据的源代码,这些源代码提供了读写结构数据的接口,从而能够构造、初始化、读取、序列化、反序列化结构数据。

使用以下命令生成相应的接口代码:

// $SRC_DIR: .proto所在的源目录
// --cpp_out: 生成C++代码
// $DST_DIR: 生成代码的目标目录
// xxx.proto: 要针对哪个proto文件生成接口代码

protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/xxx.proto

编译完成后将会生成一个xxx.pb.h和xxx.pb.cpp文件,会提供类似SerializeToOstream()、set_name()、name()等方法。

3.调用接口进行序列化、反序列化

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


using namespace std;
using namespace tutorial;


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

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

        mr.SerializeToString(&data);
        cout<<"序列化后的数据["<<data.length()<<"]: "<< data << endl;
        cout<<hex<<(int)*((char*)data.c_str())<<endl;
        cout<<hex<<(int)*((char*)data.c_str() + 1)<<endl;
        //客户端发送data  send(sockfd, data.c_str(), data.length());
    }
    //服务器端接受请求
    {
        //receive(sockfd, data, ...);
        mobile_request mr;
        mr.ParseFromString(data);
        cout<<"客户端手机号码: " << mr.mobile() << endl;

    }

    return 0;
}

压缩效率高:服务器间的海量数据传输与通信,可以节省磁盘和带宽,protobuf 适合处理大数据集中的单个小消息,但并不适合处理单个的大消息。
解析速度快:可以提高服务器的吞吐能力。

项目应用

在这里插入图片描述

class MobileCodeReqEv : public iEvent	//手机验证码请求
{
public:
	MobileCodeReqEv(const std::string& mobile) :iEvent(EEVENTID_GET_MOBLIE_CODE_REQ, iEvent::generateSeqNo())		// 显式调用基类构造函数
	{
		msg_.set_mobile(mobile);
	};

	const std::string& get_mobile() { return msg_.mobile(); };	// 手机号码
	virtual std::ostream& dump(std::ostream& out) const;	// 将对象信息输出到 std::ostream 流
	virtual i32 ByteSize() { return msg_.ByteSize(); };	// 返回 msg_ 对象的字节大小
	virtual bool SerializeToArray(char* buf, int len) { return msg_.SerializeToArray(buf, len); };	// 将 msg_ 对象序列化到一个字符数组中

private:
	tutorial::mobile_request msg_;	//用于存储和操作手机验证码请求的相关信息。

};
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞大圣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值