pb网络编程_程序性能优化之网络传输与数据存储优化(五)上

f107d1d1f9186054135cea9983d71a37.png

11/12号文档资料已全面更新!;《【阿里P7】移动互联网架构师高级教程+BAT面试题》,点击下方链接前往领取:

【阿里P7】Android高级教程+BAT面试题​shimo.im

本篇文章将先从google protobuf来介绍网络传输与数据存储优化:

简介

protobuf也叫protocol buffer是google 的一种数据交换的格式,它独立于语言,独立于平台。google 提供了多种语言的实现:java、c#、c++、go 和 python,每一种实现都包含了相应语言的编译器以及库文件。由于它是一种二进制的格式,比使用 xml 、json进行数据交换快许多。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。作为一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络传输、配置文件、数据存储等诸多领域。 protobuf在各种rpc的实现上都占据重要角色。

优点

 性能好/效率高
 代码生成机制
 支持“向后兼容”和“向前兼容”
 支持多种编程语言

缺点

 应用不够广(相比xml和json)
 二进制格式导致可读性差
 缺乏自描述

安装

 github源代码下载地址:https://github.com/google/protobuf 源码包中的src/README.md, 有详细的安装说明,安装过程如下: 1、解压压缩包:unzip protobuf-master.zip 2、进入解压后的文件夹:cd protobuf-master 3、安装所需工具:sudo apt-get install autoconf automake libtool curl make g++ unzip 4、自动生成configure配置文件:./autogen.sh 5、配置环境:./configure 6、编译源代码(时间比较长):make 7、安装:sudo make install 8、刷新动态库:sudo ldconfig

编译.proto文件

 protoc:protobuf自带的编译工具,将.proto文件生成指定的类
 –cpp_out:将生成的C++代码文件放到等号后面指定的目录,这里也指定当前目录

通过protoc工具编译.proto文件时,编译器将生成所选择语言的代码,这些代码可以操作在.proto文件中定义的消息类型,包括获取、设置字段值,将消息序列化到一个输出流中,以及从一个输入流中解析消息。对C++来说,编译器会为每个.proto文件生成一个.h文件和一个.cc文件,.proto文件中的每一个消息有一个对应的类。

编译代码

g++ *.cpp *.c *.cc `pkg-config --cflags --libs protobuf`

 反引号(` ):反引号的作用就是将反引号内的linux命令执行
 pkg-config 是通过库提供的一个.pc文件获得库的各种必要信息的,包括版本信息、编译和连接需要的参数等。
 pkg-config –cflags protobuf:列出指定共享库的预处理和编译flags
 pkg-config –libs protobuf:列出指定共享库的链接flags

在.proto文件中定义消息格式

消息由至少一个字段组合而成,类似于C语言中的结构体,每个字段都有一定的格式:

数据类型 字段名称 = 唯一的编号标签值;

syntax = "proto3"; //指定版本信息,不指定会报错

message Person  //message为关键字,作用为定义一种消息类型
{
    string name = 1;    //姓名
    int32 id = 2;       //id
    string email = 3;   //邮件
}

数据类型

21cfa12c9278f1d48210a4ff0da152cd.png

proto文件即消息协议原型定义文件,在该文件中我们可以通过使用描述性语言,来良好的定义我们程序中需要用到数据格式。通过查看头文件,可以发现针对每个字段都会大致生成如下几种函数,以name为例。可以看出,对于每个字段会生成一个clear清除函数(clear_name)、set函数(set_name)、get函数(name和mutable_name)。

void clear_name();
void set_name(const ::std::string& value);
void set_name(const char* value);
void set_name(const char* value, size_t size);
const ::std::string& name() const;
::std::string* mutable_name();

C数组的序列化和反序列化

#include <iostream>
#include "person.pb.h"

using namespace std;

int main()
{
    char buf[1024];
    int len;

    GOOGLE_PROTOBUF_VERIFY_VERSION;

    Person obj;
    obj.set_name("gongluck");
    obj.set_id(1);
    *obj.mutable_email() = "http://blog.csdn.net/gongluck93";
    len = obj.ByteSize();
    cout << "len = " << len << endl;
    obj.SerializeToArray(buf, len);

    Person obj2;
    obj2.ParseFromArray(buf, len);
    cout << "name = " << obj2.name() << endl;
    cout << "id = " << obj2.id() << endl;
    cout << "email = " << obj2.email() << endl;

    google::protobuf::ShutdownProtobufLibrary();

    return 0;
}

C++ String的序列化和反序列化

#include <iostream>
#include "person.pb.h"

using namespace std;

int main()
{
    string str;

    GOOGLE_PROTOBUF_VERIFY_VERSION;

    Person obj;
    obj.set_name("gongluck");
    obj.set_id(1);
    *obj.mutable_email() = "http://blog.csdn.net/gongluck93";
    obj.SerializeToString(&str);

    Person obj2;
    obj2.ParseFromString(str);
    cout << "name = " << obj2.name() << endl;
    cout << "id = " << obj2.id() << endl;
    cout << "email = " << obj2.email() << endl;

    google::protobuf::ShutdownProtobufLibrary();

    return 0;
}

文件描述符序列化和反序列化

#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "person.pb.h"

using namespace std;

int main()
{
    int fd = open("./testFileDesc.xxx", O_CREAT|O_TRUNC|O_RDWR, 0664);

    GOOGLE_PROTOBUF_VERIFY_VERSION;

    Person obj;
    obj.set_name("gongluck");
    obj.set_id(1);
    *obj.mutable_email() = "http://blog.csdn.net/gongluck93";
    obj.SerializeToFileDescriptor(fd);
    fsync(fd);
    lseek(fd, 0, SEEK_SET);

    Person obj2;
    obj2.ParseFromFileDescriptor(fd);
    cout << "name = " << obj2.name() << endl;
    cout << "id = " << obj2.id() << endl;
    cout << "email = " << obj2.email() << endl;

    google::protobuf::ShutdownProtobufLibrary();

    return 0;
}

C++ stream 序列化和反序列化

#include <iostream>
#include <fstream>
#include "person.pb.h"

using namespace std;

int main()
{
    fstream file("testStream.xxx", ios::in|ios::out|ios::trunc|ios::binary);

    GOOGLE_PROTOBUF_VERIFY_VERSION;

    Person obj;
    obj.set_name("gongluck");
    obj.set_id(1);
    *obj.mutable_email() = "http://blog.csdn.net/gongluck93";
    obj.SerializeToOstream(&file);
    file.flush();
    file.seekg(0, ios::beg);

    Person obj2;
    obj2.ParseFromIstream(&file);
    cout << "name = " << obj2.name() << endl;
    cout << "id = " << obj2.id() << endl;
    cout << "email = " << obj2.email() << endl;

    google::protobuf::ShutdownProtobufLibrary();

    file.close();

    return 0;
}

repeated限定修饰符

repeated 代表可重复,我们可以理解为数组。

syntax = "proto3";

message Person
{
    string name = 1;
    int32 id = 2;
    string email = 3;
}

message AddressBook
{
    repeated Person people = 1;
}

而对于字段修饰符为repeated的字段生成的函数,则稍微有一些不同,如people字段,则编译器会为其产生如下的代码:

int people_size() const;
void clear_people();
const ::Person& people(int index) const;
::Person* mutable_people(int index);
::Person* add_people();
::google::protobuf::RepeatedPtrField< ::Person >* mutable_people();
const ::google::protobuf::RepeatedPtrField< ::Person >& people() const;

例子

#include <iostream>
#include <fstream>
#include "person.pb.h"

using namespace std;

int main()
{
    fstream file("testStream.xxx", ios::in|ios::out|ios::trunc|ios::binary);

    GOOGLE_PROTOBUF_VERIFY_VERSION;

    AddressBook obj;

    Person* p1 = obj.add_people();
    p1->set_name("gongluck");
    p1->set_id(1);
    *(p1->mutable_email()) = "http://blog.csdn.net/gongluck93";

    Person* p2 = obj.add_people();
    p2->set_name("panzhikun");
    p2->set_id(2);
    *(p2->mutable_email()) = "panzhikun@gg.com";

    obj.SerializeToOstream(&file);
    file.flush();
    file.seekg(0, ios::beg);

    AddressBook obj2;
    obj2.ParseFromIstream(&file);
    for(int i= 0; i< obj.people_size(); ++i)
    {
        Person per = obj2.people(i);
        cout << "name = " << per.name() << endl;
        cout << "id = " << per.id() << endl;
        cout << "email = " << per.email() << endl;
    }

    google::protobuf::ShutdownProtobufLibrary();

    file.close();

    return 0;
}

枚举

syntax = "proto3";

message Person
{
    string name = 1;
    int32 id = 2;
    string email = 3;

    enum PhoneType
    {
        MOBLIE = 0;//首成员必须为0
        HOME = 1;
        WORK = 2;
    }
    message PhoneNumber
    {
        string number = 1;
        PhoneType type = 2;
    }
    repeated PhoneNumber phones = 4;
}

message AddressBook
{
    repeated Person people = 1;
}

·例子

#include <iostream>
#include <fstream>
#include "person.pb.h"

using namespace std;

int main()
{
    fstream file("testStream.xxx", ios::in|ios::out|ios::trunc|ios::binary);

    GOOGLE_PROTOBUF_VERIFY_VERSION;

    AddressBook obj;

    Person* p1 = obj.add_people();
    p1->set_name("gongluck");
    p1->set_id(1);
    *(p1->mutable_email()) = "http://blog.csdn.net/gongluck93";

    Person::PhoneNumber* phone1 = p1->add_phones();
    phone1->set_number("110");
    phone1->set_type(Person::MOBLIE);
    Person::PhoneNumber* phone2 = p1->add_phones();
    phone2->set_number("120");
    phone2->set_type(Person::WORK);

    obj.SerializeToOstream(&file);
    file.flush();
    file.seekg(0, ios::beg);

    AddressBook obj2;
    obj2.ParseFromIstream(&file);
    for(int i= 0; i< obj.people_size(); ++i)
    {
        Person per = obj2.people(i);
        cout << "name = " << per.name() << endl;
        cout << "id = " << per.id() << endl;
        cout << "email = " << per.email() << endl;
        for(int j=0; j< per.phones_size(); ++j)
        {
            Person::PhoneNumber phonenum= per.phones(j);
            switch(phonenum.type())
            {
            case Person::MOBLIE:
                cout << "mobile : " ;
                break;
            case Person::WORK:
                cout << "work : ";
                break;
            case Person::HOME:
                cout << "home : ";
                break;
            default:
                cout << "Not Know : ";
                break;
            }
            cout << phonenum.number() << endl;
        }
    }

    google::protobuf::ShutdownProtobufLibrary();

    file.close();

    return 0;
}

 .proto文件新增一个可选的package声明符,用来防止不同的消息类型有命名冲突。包的声明符会根据使用语言的不同影响生成的代码。对于C++,产生的类会被包装在C++的命名空间中。

syntax = "proto3";

package Test;//package

message Person
{
    string name = 1;
    int32 id = 2;
    string email = 3;

    enum PhoneType
    {
        MOBLIE = 0;//首成员必须为0
        HOME = 1;
        WORK = 2;
    }
    message PhoneNumber
    {
        string number = 1;
        PhoneType type = 2;
    }
    repeated PhoneNumber phones = 4;
}

message AddressBook
{
    repeated Person people = 1;
}

例子

using namespace Test;
#include <iostream>
#include <fstream>
#include "person.pb.h"

using namespace std;
using namespace Test;

int main()
{
    fstream file("testStream.xxx", ios::in|ios::out|ios::trunc|ios::binary);

    GOOGLE_PROTOBUF_VERIFY_VERSION;

    AddressBook obj;

    Person* p1 = obj.add_people();
    p1->set_name("gongluck");
    p1->set_id(1);
    *(p1->mutable_email()) = "http://blog.csdn.net/gongluck93";

    Person::PhoneNumber* phone1 = p1->add_phones();
    phone1->set_number("110");
    phone1->set_type(Person::MOBLIE);
    Person::PhoneNumber* phone2 = p1->add_phones();
    phone2->set_number("120");
    phone2->set_type(Person::WORK);

    obj.SerializeToOstream(&file);
    file.flush();
    file.seekg(0, ios::beg);

    AddressBook obj2;
    obj2.ParseFromIstream(&file);
    for(int i= 0; i< obj.people_size(); ++i)
    {
        Person per = obj2.people(i);
        cout << "name = " << per.name() << endl;
        cout << "id = " << per.id() << endl;
        cout << "email = " << per.email() << endl;
        for(int j=0; j< per.phones_size(); ++j)
        {
            Person::PhoneNumber phonenum= per.phones(j);
            switch(phonenum.type())
            {
            case Person::MOBLIE:
                cout << "mobile : " ;
                break;
            case Person::WORK:
                cout << "work : ";
                break;
            case Person::HOME:
                cout << "home : ";
                break;
            default:
                cout << "Not Know : ";
                break;
            }
            cout << phonenum.number() << endl;
        }
    }

    google::protobuf::ShutdownProtobufLibrary();

    file.close();

    return 0;
}

导入定义

syntax = "proto3";//指定版本信息,不指定会报错

import "info.proto"; //导入定义

package tutorial; //package声明符

message Person //message为关键字,作用为定义一种消息类型
{
    string name = 1;    //姓名
    int32 id = 2;       //id
    string email = 3; //邮件

    enum PhoneType //枚举消息类型
    {
        MOBILE = 0; //proto3版本中,首成员必须为0,成员不应有相同的值
        HOME = 1;
        WORK = 2;
    }

    message PhoneNumber
    {
        string number = 1;
        PhoneType type = 2;
    }

    repeated PhoneNumber phones = 4; //phones为数组

    //info定义在"info.proto"
    //类型格式:包名.信息名
    infopack.info tmp = 5;
}

message AddressBook
{
    repeated Person people = 1;
}

原文链接 https://cloud.tencent.com/developer/article/1056432

最后

我们今年整理了一份阿里P7级别的Android架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。

主要包括腾讯,以及字节跳动,华为,小米,等一线互联网公司主流架构技术。如果你有需要,尽管拿走好了。

以下为我们整理的资料免费分享;【阿里P7】Android高级教程+BAT面试题

1.Android高级技术脑图

2.P7级Android高级架构视频教程

3.Android核心高级技术PDF文档+BAT大厂面试真题解析

4.Android思维脑图(技能树)

1.Android高级技术脑图;

查漏补缺,体系化深入学习提升

2012fd1c0020eade2597baff85e0b337.png

2.【Android高级架构视频教程】;

340a89e0734632dc6dd94c3f0f09dbae.png

全套部分展示;

java与Android内核进阶专题视频与源码

3787ef426375b15cea7e89002de8550b.png

384dc8383108e300758e7efc1b2303fb.png

阿里P7级全套高级学习视频;

a6ac60ecbd976ddc3361896406b87600.png

3.Android核心高级技术PDF文档,BAT大厂面试真题解析

7fa769fe2cf6281b80530c3b708ff10f.png

f8f2eceee713919506c4567437ec04c8.png

4.Android思维脑图(技能树)

f14218cfaa9d2f1ee81276cfff220ef0.png

免费分享

在评论区留言或者私信我,视频教程,BAT面试真题解析文档,我看到都会回复的


也可以点击下方链接前往领取:

【阿里P7】Android高级教程+BAT面试题​shimo.im
9eaeeccdaf3b7f5714e9257fd77c68c9.png

为什么免费分享?

很多开发人员工作几年,技术薪资均没有提升。
程序开发是吃青春饭的工作,有很多志在学习提升,却又苦于找不到学习方向和路线的开发人员。
希望大家通过我分享的这套高级架构资料,结合自身不足、重点学习、系统学习、早日进阶成为Android高级架构师。实现个人理想和创造更多价值。
不负青春对我们的期待,不负时代对我们鞭策。

Android架构师之路很漫长,一起共勉吧!喜欢的话别忘记点击关注和赞哦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值