精华内容
下载资源
问答
  • 博文地址:https://blog.csdn.net/yhx956058885/article/details/108101292
  • protocolbuffer(以下简称PB)是google 的一种数据交换的格式,它独立于语言,独立于平台 提供了多种语言的实现:java、c#、c++、go 和 python,是一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络...
  • 谷歌protobuf的使用一、概述二、安装 一、概述 Protocol buffers 是 Google 的语言中立、平台中立、可扩展的结构化数据序列化机制——想想 XML,但更小、更快、更简单。您可以定义一次数据的结构化方式,然后您...

    一、概述

    1. Protocol buffers 是 Google 的语言中立、平台中立、可扩展的结构化数据序列化机制——像 XML,但更小、更快、更简单。您可以定义一次数据的结构化方式,然后您可以使用特殊生成的源代码轻松地使用各种语言在各种数据流中写入和读取结构化数据。
    2. Photocol buffers 是一种比json和xml等序列化工具更加轻量和高效的结构化数据存储格式,性能比json和xml真的强很多。
    3. 原理图:
      protobuf 原理图

    二、安装

    # 如果在解压或安装时出现问题,执行
    apt-get install autoconf automake libtool curl make g++ unzip
    # 1. 从github上克隆protobuf
    git clone https://github.com/protocolbuffers/protobuf
    # 2. 解压下载好的文件
    unzip protobuf-master.zip
    # 3. 进入 protobuf-master 目录
    cd protobuf-master/
    # 4. 执行如下命令
    ./autogen.sh
    ./configure
    make
    make check
    make install
    ldconfig
    # 5. 在 shell 下输入protoc ,如果出现 Usage: protoc [OPTION] PROTO_FILES 则成功。
    

    三、protobuf中的限定符

    限定符含义
    required必填字段
    optional可选字段
    repeated可重复字段

    四、protobuf支持的数据类型

    protobuf数据类型代表C++数据类型描述
    floatfloat
    doubledouble
    int32__int32使用变长编码,对于负值的效率很低,如果你的域有可能有负值,请使用sint64替代
    uint32unsigned __int32使用变长编码
    int64__int64使用变长编码
    uint64unsigned __int64使用变长编码
    sint32__int32使用变长编码,这些编码在负值时比int32高效的多
    sint64__int64使用变长编码,有符号的整型值。编码时比通常的int64高效。
    fixed32unsigned __int32总是4个字节,如果数值总是比228大的话,这个类型会比uint32高效。
    fixed64unsigned __int64总是8个字节,如果数值总是比总是比256大的话,这个类型会比uint64高效。
    sfixed32__int32总是4个字节
    sfixed64__int64总是8个字节
    boolbool
    stringstd::string一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。
    bytesstd::string可能包含任意顺序的字节数据。
    enumenum枚举类型。如果要将两个枚举变量的值设为相等,那么需要添加如下代码,否则会报错:option allow_alias = true;

    五、编译

    1. 将proto文件编译成 C++ 文件

    # SRC_DIR: proto文件(example.proto)所在目录
    # cpp_out(DST_DIR): 制定了生成代码的路径
    # example.proto: 指proto文件名
    protoc -I=$SRC_DIR --cpp_out=$DST_DIR  example.proto
    
    # 示例:
    protoc -I=./ --cpp_out=./ example.proto
    # 说明:在当前目录中查找 example.proto 并将生成的文件放在当前目录下
    

    2. 将编译好的文件与代码一起编译执行

    g++  -std=c++11   example.cc example.pb.cc -lprotobuf
    

    六、应用

    1. proto 文件的编写(文件后缀名:proto)

    syntax = "proto2";
    
    package example;
    
    // 使用手机号登录获取验证码(请求端)
    message get_code_requset {
    	required	string	mobile	= 1;
    }
    
    // 使用手机号登录获取验证码(响应端)
    message get_code_response {
    	required	int32	code	= 1;	// 响应代号
    	required	int32	icode	= 2;	// 验证码
    	optional	string	reason	= 3;	// 失败原因
    }
    
    // 使用手机号登录(请求端)
    message login_request {
    	required	string	mobile	= 1;	// 手机号码
    	required	int32	icode	= 2;	// 验证码
    }
    
    // 使用手机号登录(响应端)
    message login_response {
    	required	int32	code	= 1;	// 响应代号
    	optional	string	reason	= 2;	// 失败原因
    }
    
    // 查询登录记录(请求端)
    message login_record_request {
    	required	string	mobile	= 1;	// 手机号码
    }
    
    // 查询登录记录(响应端)
    message login_record_response {
    	required	int32	code	= 1;	// 响应代号
    	optional	string	reason	= 2;	// 失败原因
    	
    	message login_record {
    		required	int32	timestamp	= 1;	// 时间戳
    		required	string	device_name	= 2;	// 设备名
    	}
    
    	repeated	login_record	records	= 3;
    }
    
    // 将以上代码编译成 C++ 文件
    // protoc -I=./ --cpp_out=./ example.proto
    

    2. 基础应用

    #include <string>
    #include <iostream>
    #include "example.pb.h"
    
    int main(int argc, char *argv[]) {
    	std::string data;	// 存储序列化之后的数据
    
    	// 客户端发送请求
    	{
    		example::get_code_requset getCodeRequest;
    		getCodeRequest.set_mobile("19912341234");
    
    		getCodeRequest.SerializeToString(&data);
    		std::cout << "serial[" << data.length() << "]:" << data << std::endl;
    	}
    
    	// 服务器端解析数据
    	{
    		example::get_code_requset parse;
    		parse.ParseFromString(data);
    		std::cout << "mobile: " << parse.mobile() << std::endl;
    	}
    	return 0;
    }
    
    /*********************************************************************************************
     * 使用如下语句在shell下编译:g++ -std=c++11 example.cc example.pb.cc -o example.exe -lprotobuf
    **********************************************************************************************/
    

    3. 嵌套应用(即message内嵌套message)

    #include <time.h>
    #include <string>
    #include <iostream>
    #include "example.pb.h"
    
    int main(int argc, char *argv[]) {
    	std::string data;	// 存储序列化之后的数据
    
    	// 客户端发送请求
    	{
    		example::login_record_response response;
    		response.set_code(200);
    		response.set_reason("OK");
    
    		// 插入登录数据
    		time_t now = time(NULL);
    		for (int i = 0; i < 5; ++i) {
    			example::login_record_response_login_record* login = response.add_records();
    			login->set_timestamp(now + i);
    			login->set_device_name(std::string("phone-") + std::to_string(i));
    		}
    
    		std::cout << "record size: " << response.records_size() << std::endl;
    
    		// 序列化
    		response.SerializeToString(&data);
    	}
    
    	// 服务器端解析数据
    	{
    		example::login_record_response response;
    		response.ParseFromString(data);
    
    		std::cout << "code: " << response.code()
    			<< "  reason:" << response.reason()
    			<< "  parse size : " << response.records_size() << std::endl;
    
    		for (int i = 0; i < response.records_size(); ++i) {
    			const example::login_record_response_login_record& login = response.records(i);
    			std::cout << "timestamp: " << login.timestamp()
    				<< "  device_name: " << login.device_name() << std::endl;
    		}
    
    	}
    
    	return 0;
    }
    
    /*********************************************************************************************
     * 使用如下语句在shell下编译:g++ -std=c++11 example.cc example.pb.cc -o example.exe -lprotobuf
    **********************************************************************************************/
    

    4. libevent 和 protobuf 协作

    1. 客户端
    // 函数 cmd_read_data() 和 socket_read_data()
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <assert.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <event.h>
    #include <event2/event.h>
    
    #include <string>
    #include "example.pb.h"
    
    typedef struct sockaddr		sockaddr_t;
    typedef struct sockaddr_in	sockaddr_in_t;
    
    int connect_server(const char* server_ip, int port);
    
    void cmd_read_data(int fd, short events, void* arg);
    void socket_read_data(int fd, short events, void* arg);
    
    int main(int argc, char* argv[]) {
    	if (argc < 3) {
    		fprintf(stderr, "please input [ipaddr][ipport]\n");
    		return -1;
    	}
    
    	int sockfd = connect_server(argv[1], atoi(argv[2]));
    	if (sockfd < 0) {
    		fprintf(stderr, "connect_server(): failed!\n");
    		return -2;
    	}
    
    	printf("connect server success!\n");
    
    	struct event_base* base = event_base_new();
    	struct event* ev_sockfd = event_new(base, sockfd, EV_READ | EV_PERSIST, socket_read_data, NULL);
    	event_add(ev_sockfd, NULL);
    
    	// 监听终端输入事件
    	struct event* ev_cmd = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST, cmd_read_data, (void*)(&sockfd));
    	event_add(ev_cmd, NULL);
    
    	printf("event add finished!\n");
    
    	event_base_dispatch(base);
    
    	printf("finished!\n");
    
    	return 0;
    }
    
    int connect_server(const char* server_ip, int port) {
    	int sockfd, status, save_errno;
    	sockaddr_in_t server_addr;
    
    	memset(&server_addr, 0, sizeof(sockaddr_in_t));
    
    	server_addr.sin_family = AF_INET;
    	server_addr.sin_port = htons(port);
    	status = inet_aton(server_ip, &server_addr.sin_addr);
    
    	if (!status) {
    		errno = EINVAL;
    		fprintf(stderr, "inet_aton() failed!\n");
    		return -1;
    	}
    
    	sockfd = socket(PF_INET, SOCK_STREAM, 0);
    	if (sockfd < 0) {
    		fprintf(stderr, "socket() failed! reason: %s\n", strerror(errno));
    		return sockfd;
    	}
    
    	status = connect(sockfd, (sockaddr_t*)(&server_addr), sizeof(server_addr));
    	if (status < 0) {
    		fprintf(stderr, "connect() failed! reason: %s\n", strerror(errno));
    		save_errno = errno;
    		close(sockfd);
    		errno = save_errno;
    		return -1;
    	}
    
    	// 不用设置非阻塞
    	//evutil_make_socket_nonblocking(sockfd);
    
    	return sockfd;
    }
    
    void cmd_read_data(int fd, short events, void* arg) {
    	std::string data;
    	char msg[1024] = { 0 };
    
    	read(fd, msg, sizeof(msg) - 1);
    
    	// 向服务器发送手机号
    	example::get_code_requset request;
    	request.set_mobile("19912344321");
    	request.SerializeToString(&data);
    
    	int sockfd = *((int*)arg);
    
    	// 把终端消息发送给服务器端,客户端忽略性能考虑,直接使用阻塞发送
    	write(sockfd, data.c_str(), data.length());
    }
    
    void socket_read_data(int fd, short events, void* arg) {
    	char msg[1024];
    
    	// 不考虑数据读了一半的情况
    	int len = read(fd, msg, sizeof(msg) - 1);
    	if (len == 0) {
    		fprintf(stderr, "connection close!\n");
    		exit(2);
    	}
    	else if (len < 0) {
    		fprintf(stderr, "read failed!\n");
    		exit(3);
    	}
    
    	msg[len] = '\0';
    
    	example::get_code_response response;
    	response.ParseFromString(std::string(msg));
    
    	printf("code: %d, icode: %d, reason: %s\n", response.code(), response.icode(), response.reason().c_str());
    }
    
    
    
    1. 服务器端
    // 函数:do_recv_msg()
    #include <string.h>
    #include <stdlib.h>
    #include <event.h>
    #include <event2/event.h>
    #include <event2/listener.h>
    #include <event2/bufferevent.h>
    
    #include <string>
    #include <iostream>
    #include "example.pb.h"
    
    #define BUFFER_LENGTH 1024
    
    typedef struct event_base		event_base_t;
    typedef struct bufferevent		bufferevent_t;
    typedef struct evconnlistener	evconnlistener_t;
    
    typedef struct _connect_stat {
    	bufferevent_t* bev;
    	char buffer[BUFFER_LENGTH];
    }connect_stat_t;
    
    connect_stat_t* stat_new(bufferevent_t* bev);
    
    void listener_cb(evconnlistener_t* listener, evutil_socket_t fd, struct sockaddr* addr, int addrlen, void* user_arg);
    
    void do_recv_msg(bufferevent_t* bev, void* user_arg);
    void event_cb(bufferevent_t* bev, short what, void* user_arg);
    
    int main(int argc, char* argv[]) {
    	struct sockaddr_in sin;
    	memset(&sin, 0, sizeof(sin));
    	sin.sin_family = AF_INET;
    	sin.sin_port = htons(9696);	// 端口为 9696
    	//sin.sin_addr.s_addr = htonl(INADDR_ANY);
    
    	event_base_t* base = event_base_new();
    
    	struct evconnlistener* listener = evconnlistener_new_bind(base, listener_cb, base,
    		BEV_OPT_CLOSE_ON_FREE,
    		10, (struct sockaddr*)(&sin), sizeof(sin));
    
    	event_base_dispatch(base);
    
    	evconnlistener_free(listener);
    	event_base_free(base);
    
    	return 0;
    }
    
    connect_stat_t* stat_new(bufferevent_t* bev) {
    	connect_stat_t* p = (connect_stat_t*)malloc(sizeof(connect_stat_t));
    	memset(p, 0, sizeof(connect_stat_t));
    	p->bev = bev;
    
    	return p;
    }
    
    void listener_cb(evconnlistener_t* listener, evutil_socket_t fd, struct sockaddr* addr, int addrlen, void* user_arg) {
    	event_base_t* base = (event_base_t*)(user_arg);
    
    	// 为客户端分配bufferevent
    	bufferevent_t* bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    
    	connect_stat_t* stat = stat_new(bev);
    
    	bufferevent_setcb(bev, do_recv_msg, NULL, event_cb, stat);
    	bufferevent_enable(bev, EV_READ | EV_PERSIST);
    }
    
    void do_recv_msg(bufferevent_t* bev, void* user_arg) {
    	connect_stat_t* stat = (connect_stat_t*)user_arg;
    
    	char* msg = stat->buffer;
    
    	size_t len = bufferevent_read(bev, msg, BUFFER_LENGTH - 1);
    	msg[len] = '\0';
    
    	example::get_code_requset request;
    	request.ParseFromString(std::string(msg));
    
    	std::cout << "mobile: " << request.mobile() << std::endl;
    
    	// 响应
    	std::string data;
    	example::get_code_response response;
    	int icode = rand() % 100000 + 100000;
    	response.set_code(200);
    	response.set_icode(icode);
    	response.set_reason("OK");
    	response.SerializeToString(&data);
    
    	bufferevent_write(bev, data.c_str(), data.length());
    }
    
    void event_cb(bufferevent_t* bev, short what, void* user_arg) {
    	connect_stat_t* stat = (connect_stat_t*)user_arg;
    
    	if (what & BEV_EVENT_EOF) {
    		printf("connection closed!\n");
    	}
    	else if (what & BEV_EVENT_ERROR) {
    		printf("some other error!\n");
    	}
    
    	// 同时 关闭套接字 和 free 读写缓冲区
    	bufferevent_free(bev);
    
    	free(stat);
    }
    
    展开全文
  • google protobuf是一个灵活的、高效的用于序列化数据的协议。相比较XML和JSON格式,protobuf更小、更快、更便捷。google protobuf是跨语言的,并且自带了一个编译器(protoc),只需要用它进行编译,可以编译成Java、...

      google protobuf是一个灵活的、高效的用于序列化数据的协议。相比较XML和JSON格式,protobuf更小、更快、更便捷。google protobuf是跨语言的,并且自带了一个编译器(protoc),只需要用它进行编译,可以编译成Java、python、C++、C#、Go等代码,然后就可以直接使用,不需要再写其他代码,自带有解析的代码。更详细的介绍见: Protocol Buffers

    protobuf安装

    1、下载protobuf代码 google/protobuf

    2、安装protobuf

      tar -xvf protobuf

      cd protobuf

      ./configure --prefix=/usr/local/protobuf

      make

      make check

      make install

    至此安装完成^_^,下面是配置:

    (1) vim /etc/profile,添加

      export PATH=$PATH:/usr/local/protobuf/bin/

      export PKG_CONFIG_PATH=/usr/local/protobuf/lib/pkgconfig/

      保存执行,source /etc/profile。同时在~/.profile中添加上面两行代码,否则会出现登录用户找不到protoc命令。

    (2) 配置动态链接库

      vim /etc/ld.so.conf,在文件中添加/usr/local/protobuf/lib(注意: 在新行处添加),然后执行命令: ldconfig

     .proto文件

      .proto文件是protobuf一个重要的文件,它定义了需要序列化数据的结构。使用protobuf的3个步骤是:

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

    2 用protobuf编译器编译.proto文件

    3 用C++/Java等对应的protobuf API来写或者读消息

    程序示例(C++版)

      该程序示例的大致功能是,定义一个Persion结构体和存放Persion的AddressBook,然后一个写程序向一个文件写入该结构体信息,另一个程序从文件中读出该信息并打印到输出中。

    1 address.proto文件

    复制代码

    package tutorial;
    
    message Persion {
        required string name = 1;
        required int32 age = 2;
    }
    
    message AddressBook {
        repeated Persion persion = 1;
    }

    复制代码

      编译.proto文件,执行命令: protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto,示例中执行命令protoc --cpp_out=/tmp addressbook.proto ,会在/tmp中生成文件addressbook.pb.h和addressbook.pb.cc。

    2 write.cpp文件,向文件中写入AddressBook信息,该文件是二进制的

    复制代码

     1 #include <iostream>
     2 #include <fstream>
     3 #include <string>
     4 #include "addressbook.pb.h"
     5 
     6 using namespace std;
     7 
     8 void PromptForAddress(tutorial::Persion *persion) {
     9     cout << "Enter persion name:" << endl;
    10     string name;
    11     cin >> name;
    12     persion->set_name(name);
    13 
    14     int age;
    15     cin >> age;
    16     persion->set_age(age);
    17 }
    18 
    19 int main(int argc, char **argv) {
    20     //GOOGLE_PROTOBUF_VERIFY_VERSION;
    21 
    22     if (argc != 2) {
    23         cerr << "Usage: " << argv[0] << " ADDRESS_BOOL_FILE" << endl;
    24         return -1;
    25     }
    26 
    27     tutorial::AddressBook address_book;
    28 
    29     {
    30         fstream input(argv[1], ios::in | ios::binary);
    31         if (!input) {
    32             cout << argv[1] << ": File not found. Creating a new file." << endl;
    33         }
    34         else if (!address_book.ParseFromIstream(&input)) {
    35             cerr << "Filed to parse address book." << endl;
    36             return -1;
    37         }
    38     }
    39 
    40     // Add an address
    41     PromptForAddress(address_book.add_persion());
    42 
    43     {
    44         fstream output(argv[1], ios::out | ios::trunc | ios::binary);
    45         if (!address_book.SerializeToOstream(&output)) {
    46             cerr << "Failed to write address book." << endl;
    47             return -1;
    48         }
    49     }
    50 
    51     // Optional: Delete all global objects allocated by libprotobuf.
    52     //google::protobuf::ShutdownProtobufLibrary();
    53 
    54     return 0;
    55 }

    复制代码

      编译write.cpp文件,g++ addressbook.pb.cc write.cpp -o write `pkg-config --cflags --libs protobuf` (注意,这里的`符号在键盘数字1键左边,也就是和~是同一个按键)。

    3 read.cpp文件,从文件中读出AddressBook信息并打印

    复制代码

     1 #include <iostream>
     2 #include <fstream>
     3 #include <string>
     4 #include "addressbook.pb.h"
     5 
     6 using namespace std;
     7 
     8 void ListPeople(const tutorial::AddressBook& address_book) {
     9     for (int i = 0; i < address_book.persion_size(); i++) {
    10         const tutorial::Persion& persion = address_book.persion(i);
    11 
    12         cout << persion.name() << " " << persion.age() << endl;
    13     }
    14 }
    15 
    16 int main(int argc, char **argv) {
    17     //GOOGLE_PROTOBUF_VERIFY_VERSION;
    18 
    19     if (argc != 2) {
    20         cerr << "Usage: " << argv[0] << " ADDRESS_BOOL_FILE" << endl;
    21         return -1;
    22     }
    23 
    24     tutorial::AddressBook address_book;
    25 
    26     {
    27         fstream input(argv[1], ios::in | ios::binary);
    28         if (!address_book.ParseFromIstream(&input)) {
    29             cerr << "Filed to parse address book." << endl;
    30             return -1;
    31         }
    32         input.close();
    33     }
    34 
    35     ListPeople(address_book);
    36 
    37     // Optional: Delete all global objects allocated by libprotobuf.
    38     //google::protobuf::ShutdownProtobufLibrary();
    39 
    40     return 0;
    41 }

    复制代码

       编译read.cpp文件,g++ addressbook.pb.cc read.cpp -o read `pkg-config --cflags --libs protobuf`

    4 执行程序

     

    展开全文
  • 谷歌protobuf简介

    千次阅读 2019-06-27 19:29:01
    最近在工作中用到了Google protobuf,感觉比xml以及json好用很多,具体介绍可以参考Google protobuf简介

    最近在工作中用到了Google protobuf,感觉比xml以及json好用很多,具体介绍可以参考Google protobuf简介

    展开全文
  • 该rar文件内包括Encoding.pdf(编码)、Language Guide.pdf(语言指南)、Protocol Buffer Basics - Java.pdf(Protocol Buffer 基础: Java)、Protocol Buffers Developer Guide.pdf(开发指南)、Protocol Buffers...
  • 使用方法也比较简单:定义用于消息文件.proto使用protobuf的编译器编译消息文件使用编译好对应语言的类文件进行消息的序列化与反序列化先来定义一个简单的消息:message Person {int32 id = 1;//24string name = 2;//...

    使用方法也比较简单:

    定义用于消息文件.proto

    使用protobuf的编译器编译消息文件

    使用编译好对应语言的类文件进行消息的序列化与反序列化

    先来定义一个简单的消息:

    message Person {

    int32 id = 1;//24

    string name = 2;//wujingchao

    string email = 3;//wujingchao92@gmail.com

    }

    实际的二进制消息为:

    08 18 12 0a 77 75 6a 69 6e 67 63 68 61 6f 1a 16 77 75 6a 69 6e 67 63 68 61 6f 39 32 40 67 6d 61 69 6c 2e 63 6f 6d

    下面就讲解这段二进制流数据是怎么组成的:

    varints

    一般情况下int类型都是固定4个字节,protobuf定义了一种变长的int,每个字节最高位表示后面还有没有字节,低7位就为实际的值,并且使用小端的表示方法。例如1,varint的表示方法就为:

    0000 0001

    是不是这样就省了三个字节。

    再例如300,4字节表示为:10 0101100,varint表示为:

    10101100 00000010

    所以前面消息为Person的id的值为00011000,即0x18。

    负数的最高位为1,如果负数也使用这种方式表示就会出现一个问题,int32总是需要5个字节,int64总是需要10个字节。

    所以定义了另外一种类型:sint32,sint64。采用ZigZag编码,所有的负数都使用正数表示,计算方式:

    sint32

    (n << 1)^ (n >> 31)

    sint64

    (n << 1)^ (n >> 63)

    Signed OriginalEncoded As

    0

    0

    -1

    1

    1

    2

    -2

    3

    2147483647

    4294967294

    -2147483648

    4294967295

    使用varint编码的类型有int32, int64, uint32, uint64, sint32, sint64, bool, enum。Java里面没有对应的无符号类型,int32与uint32一样。

    Wire Type

    每个消息项前面都会有对应的tag,才能解析对应的数据类型,表示tag的数据类型也是varint。

    tag的计算方式: (field_number << 3) | wire_type

    每种数据类型都有对应的wire_type:

    Wire TypeMeaning Used For

    0

    varint int32, int64, uint32, uint64, sint32, sint64, bool, enum

    1

    64-bit fixed64, sfixed64, double

    2

    Length-delimited string, bytes, embedded messages, packed repeated fields

    3

    Start group groups (deprecated)

    4

    End group groups (deprecated)

    5

    32-bit fixed32, sfixed32, float

    所以wire_type最多只能支持8种,目前有6种。

    所以前面Person的id,field_number为1,wire_type为0,所以对应的tag为

    1 <<< 3 | 0 = 0x08

    Person的name,field_number为2,wire_type为2,所以对应的tag为

    2 <<< 3 | 2 = 0x12

    对应Length-delimited的wire type,后面紧跟着的varint类型表示数据的字节数。

    所以name的tag后面紧跟的0x0a表示后面的数据长度为10个字节,即"wujingchao"的UTF-8 编码或者ASCII值:

    08 18 12 0a 77 75 6a 69 6e 67 63 68 61 6f 1a 16

    嵌套的消息类型embedded messages与packed repeated fields也是使用这种方式表示,对应默认值的数据,是不会写进protobuf消息里面的。

    packed repeated与repeated的区别在于编码方式不一样,repeated将多个属性类型与值分开存储。而packed repeated采用Length-delimited方式。下面这个是官方文档的例子:

    message Test4 {

    repeated int32 d = 4 [packed=true];

    }

    22 // tag (field number 4, wire type 2)

    06 // payload size (6 bytes)

    03 // first element (varint 3)

    8E 02 // second element (varint 270)

    9E A7 05 // third element (varint 86942)

    如果没有packed的属性是这样存储的:

    20 //tag(field number 4,wire type 0)

    03 //first element (varint 3)

    20 //tag(field number 4,wire type 0)

    8E 02//second element (varint 270)

    20 //tag(field number 4,wire type 0)

    9E A7 05 // third element (varint 86942)

    是不是这种方式比较节省内存,所以proto3的repeated默认就是使用packed这种方式来存储。(proto2与proto3区别在于.proto的语法)。

    展开全文
  • 1、下载后解压缩得到protobuf-dt-master文件夹; 2、点击eclipse的菜单,帮助---安装新文件---增加---位置,选择到“protobuf-dt-master\update-site”; 3、后面的操作就是“下一步”之类的,唯一注意的是在三个...
  • Google ProtoBuf用法

    千次阅读 2019-01-10 10:57:40
    Google Protobuf是Netty中常用的编解码工具,Protobuf支持数据结构化一次可以到处使用,且可以跨语言使用,通过代码生成工具可以生成不同语言版本的源代码,还可以在使用不同版本的数据结构进程间进行数据传递,实现...
  • protobufGoogle Protobuf的纯Elixir实现
  • jprotobuf, 一个使用谷歌protobuf的java程序员实用实用程序 jprotobuf插件生成状态 #####What 是 jprotobuf#####一个使用谷歌protobuf的java程序员实用实用程序扫描类上的注解的信息,进行分析( 与protobuf读取proto...
  • ProtocolBuffer是用于结构化数据串行化的灵活、高效、自动的方法,有如XML,不过它更小、更快、也更简单。你可以定义自己的数据结构,...protobuf-java-3.2.0.jar包 太难找了,只能是自己发布一个jar包 特此分享出来
  • Google Protobuf

    2021-02-01 10:33:06
    3.Protobuf 4.Protobuf快速入门实例 5.Protobuf快速入门实例2 1.编码和解码的基本介绍 编写网络应用程序时,因为数据在网络中传输的都是二进制字节码数据,在发送数据时就需要编码,接收数据时就需要解码...
  • 下载Protobuf protobuf的github地址:https://github.com/protocolbuffers/protobuf 解压 安装 $ sudo apt-get install autoconf automake libtool curl make g++ unzip $ cd protobuf $ ./autogen.sh $ ./...
  • lua-protobuf:与Google protobuf一起使用的Lua模块
  • Google protobuf 编码解码

    2019-10-19 13:42:21
    官网 https://developers.google.com/protocol-buffers Protocol buffers are a language-neutral, platform-neutral extensible mechanism ...protobuf是一个跨语言,平台的,可以序列化结构性数据的可扩展解决...
  • google protobuf C教程

    2018-08-30 17:22:58
    google protobuf C教程,主要实现将google protobuf移植到32位单片机的教程。
  • Google 的 protocol buffers 协议(简称: protobuf) ,凭借文本体积小、支持多语言、序列化与反序列化优秀等特点在一些场景中应用广泛。本文将介绍如何实现 protobuf 中定义的 message 与 Java 的 POJO bean 的相互...
  • Google.Protobuf.dll

    2020-08-26 18:19:40
    Google.Protobuf.dll,C#用protobuf类库,用于生成和解析二进制文件 需要通过固定的proto文件格式成C#类
  • 谷歌 Google ProtoBuf用法实例

    千次阅读 2017-05-05 16:37:51
    谷歌 Google ProtoBuf用法实例
  • 最新版1.2,支持C#编译, google protobuf 文件proto的ide编写工具,原创,支持语法高亮,支持即时编译,自带简单帮助,是用来写protobuffer协议文件的最好工具,欢迎传播使用!
  • google protobuf-2.5.0

    2018-12-09 12:27:15
    protobuf-java-2.5.0.ar protobuf-2.5.0-win32 readme.txt(使用文档)
  • google ProtoBuf 做序列化/反序列化 怎么使用,随便百度 但是下载地址都还是code google的。 新列一个下载地址 github的 [b]https://github.com/google/protobuf/tags[/b] 随便哪个版本,window版 ...
  • enif_protobuf:使用enif(Erlang nif)的Google Protobuf实现
  • 2018-08-13 谷歌 protobuf-lite:3.0.1

    千次阅读 2018-08-13 14:26:00
    AndroidStudio(3.1版), 添加工程依赖到app/build.glade implementation 'com.google.protobuf:protobuf-lite:3.0.1' https://github.com/mohsenoid/protobuf_android_sample https://proandroiddev.co...
  • 最近项目忙着走Xlua热更,同事在研习中,我这边闲下来了,由于之前有学习一些golang语言,于是想着自己来编写后台、前端,用googleprotobuf,花了两三天的时间,查看了不下100个博文,以及查看google官方源码等待...
  • [转]google protobuf安装与使用

    千次阅读 2018-10-12 09:44:42
    google protobuf是一个灵活的、高效的用于序列化数据的协议。相比较XML和JSON格式,protobuf更小、更快、更便捷。google protobuf是跨语言的,并且自带了一个编译器(protoc),只需要用它进行编译,可以编译成Java、...
  • protobuf Java版本的离线api,自己制作

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 39,046
精华内容 15,618
关键字:

googleprotobuf