简介

本人也是protobuf新手,因项目需要才接触到的。开始按照官方教程整了一整天最新版的proto3,死活配置
不成功。所以直接使用了proto2。

安装

ubuntu16,04默认是带有proto2的。

通过protoc --version 可查看安装的版本。

zxp@zxp-pc:~/zxp/proto_test$ protoc --version
libprotoc 2.6.1
zxp@zxp-pc:~/zxp/proto_test$

如果提示未安装,安装即可。

sudo apt install protobuf-compiler

第一个simple

这部分代码我是参考这个博主的文章:​​点此跳转​​

使用protobuf首先我们需要定义自己的​​.proto​​文件,这个文件主要是消息类型的定义。

Ubuntu16.04安装使用protobuf2(一)_1024程序员节


simple

addressbook.proto

package tutorial;  
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;

enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}

message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}

repeated PhoneNumber phone = 4;
}

message AddressBook {
repeated Person person = 1;
}

调用protoc工具转换成接口文件。

protoc -I=./  --cpp_out=./ ./addressbook.proto

执行成功会生成一下俩文件:

addressbook.pb.cc
addressbook.pb.h

这俩文件就是接口文件,当做普通的.cpp和.h使用即可。

写入

#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;

// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person* person) {
cout << "Enter person ID number: ";
int id;
cin >> id;
person->set_id(id);
cin.ignore(256, '\n');

cout << "Enter name: ";
getline(cin, *person->mutable_name());

cout << "Enter email address (blank for none): ";
string email;
getline(cin, email);
if (!email.empty()) {
person->set_email(email);
}

while (true) {
cout << "Enter a phone number (or leave blank to finish): ";
string number;
getline(cin, number);
if (number.empty()) {
break;
}

tutorial::Person::PhoneNumber* phone_number = person->add_phone();
phone_number->set_number(number);

cout << "Is this a mobile, home, or work phone? ";
string type;
getline(cin, type);
if (type == "mobile") {
phone_number->set_type(tutorial::Person::MOBILE);
} else if (type == "home") {
phone_number->set_type(tutorial::Person::HOME);
} else if (type == "work") {
phone_number->set_type(tutorial::Person::WORK);
} else {
cout << "Unknown phone type. Using default." << endl;
}
}
}

// Main function: Reads the entire address book from a file,
// adds one person based on user input, then writes it back out to the same
// file.
int main(int argc, char* argv[]) {
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;

if (argc != 2) {
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
return -1;
}

tutorial::AddressBook address_book;

{
// Read the existing address book.
fstream input(argv[1], ios::in | ios::binary);
if (!input) {
cout << argv[1] << ": File not found. Creating a new file." << endl;
} else if (!address_book.ParseFromIstream(&input)) {
cerr << "Failed to parse address book." << endl;
return -1;
}
}

// Add an address.
PromptForAddress(address_book.add_person());

{
// Write the new address book back to disk.
fstream output(argv[1], ios::out | ios::trunc | ios::binary);
if (!address_book.SerializeToOstream(&output)) {
cerr << "Failed to write address book." << endl;
return -1;
}
}

// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();

return 0;
}

读出

#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;

// Iterates though all people in the AddressBook and prints info about them.
void ListPeople(const tutorial::AddressBook& address_book) {
for (int i = 0; i < address_book.person_size(); i++) {
const tutorial::Person& person = address_book.person(i);

cout << "Person ID: " << person.id() << endl;
cout << " Name: " << person.name() << endl;
if (person.has_email()) {
cout << " E-mail address: " << person.email() << endl;
}

for (int j = 0; j < person.phone_size(); j++) {
const tutorial::Person::PhoneNumber& phone_number = person.phone(j);

switch (phone_number.type()) {
case tutorial::Person::MOBILE:
cout << " Mobile phone #: ";
break;
case tutorial::Person::HOME:
cout << " Home phone #: ";
break;
case tutorial::Person::WORK:
cout << " Work phone #: ";
break;
}
cout << phone_number.number() << endl;
}
}
}

// Main function: Reads the entire address book from a file and prints all
// the information inside.
int main(int argc, char* argv[]) {
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;

if (argc != 2) {
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
return -1;
}

tutorial::AddressBook address_book;

{
// Read the existing address book.
fstream input(argv[1], ios::in | ios::binary);
if (!address_book.ParseFromIstream(&input)) {
cerr << "Failed to parse address book." << endl;
return -1;
}
}

ListPeople(address_book);

// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();

return 0;
}

我是使用Cmake来构建项目的。
CMakeLists.txt

我这里test1.cpp是写 test2.cpp是读

cmake_minimum_required(VERSION 3.5)

set(CMAKE_CXX_STANDARD 14)
project(write)

include_directories(
./include/
)

add_executable(write test1.cpp addressbook.pb.cc addressbook.pb.h )

target_link_libraries(write PRIVATE
protobuf
pthread
)

写的比较简陋~~~各位看官凑合凑合

编译三部曲

zxp@zxp-pc:~/zxp/proto_test$ mkdir build && cd build
zxp@zxp-pc:~/zxp/proto_test/build$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/zxp/zxp/proto_test/build
zxp@zxp-pc:~/zxp/proto_test/build$ make
[ 33%] Building CXX object CMakeFiles/write.dir/test1.cpp.o
[ 66%] Building CXX object CMakeFiles/write.dir/addressbook.pb.cc.o
[100%] Linking CXX executable write
[100%] Built target write
zxp@zxp-pc:~/zxp/proto_test/build$

编译读的,改改cmake即可。
运行
写:

zxp@zxp-pc:~/zxp/proto_test/build$ ./write file
file: File not found. Creating a new file.
Enter person ID number: 666
Enter name: 6666666
Enter email address (blank for none): 6666@6666
Enter a phone number (or leave blank to finish):
zxp@zxp-pc:~/zxp/proto_test/build$ ls
CMakeCache.txt CMakeFiles cmake_install.cmake file Makefile write

读:

zxp@zxp-pc:~/zxp/proto_test/build$ ./read file 
Person ID: 666
Name: 6666666
E-mail address: 6666@6666
zxp@zxp-pc:~/zxp/proto_test/build$

项目实际使用方式

send:

#include <iostream>
#include <fstream>
#include <string>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

#include "addressbook.pb.h"
using namespace std;

#define IP "127.0.0.1"

// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person *person)
{
cout << "Enter person ID number: ";
int id;
cin >> id;
person->set_id(id);
cin.ignore(256, '\n');

cout << "Enter name: ";
getline(cin, *person->mutable_name());

cout << "Enter email address (blank for none): ";
string email;
getline(cin, email);
if (!email.empty())
{
person->set_email(email);
}

while (true)
{
cout << "Enter a phone number (or leave blank to finish): ";
string number;
getline(cin, number);
if (number.empty())
{
break;
}

tutorial::Person::PhoneNumber *phone_number = person->add_phone();
phone_number->set_number(number);

cout << "Is this a mobile, home, or work phone? ";
string type;
getline(cin, type);
if (type == "mobile")
{
phone_number->set_type(tutorial::Person::MOBILE);
}
else if (type == "home")
{
phone_number->set_type(tutorial::Person::HOME);
}
else if (type == "work")
{
phone_number->set_type(tutorial::Person::WORK);
}
else
{
cout << "Unknown phone type. Using default." << endl;
}
}
}

int main(int argc, char *argv[])
{
GOOGLE_PROTOBUF_VERIFY_VERSION;

int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1)
{
cerr << "Error creating socket." << endl;
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(IP);
addr.sin_port = 13159;
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
cerr << "Error binding socket." << endl;
return 1;
}

tutorial::AddressBook address_book;

// Add an address.
PromptForAddress(address_book.add_person());

{
std::string message;
address_book.SerializeToString(&message);
struct sockaddr_in addrs;
addrs.sin_family = AF_INET;
addrs.sin_addr.s_addr = inet_addr(IP);
addrs.sin_port = 13157;
sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr *)&addrs, sizeof(sockaddr_in));
}
google::protobuf::ShutdownProtobufLibrary();

return 0;
}

recv:

#include <iostream>
#include <fstream>
#include <string>

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

#include "addressbook.pb.h"
using namespace std;

// Iterates though all people in the AddressBook and prints info about them.
void ListPeople(const tutorial::AddressBook &address_book)
{
for (int i = 0; i < address_book.person_size(); i++)
{
const tutorial::Person &person = address_book.person(i);

cout << "Person ID: " << person.id() << endl;
cout << " Name: " << person.name() << endl;
if (person.has_email())
{
cout << " E-mail address: " << person.email() << endl;
}

for (int j = 0; j < person.phone_size(); j++)
{
const tutorial::Person::PhoneNumber &phone_number = person.phone(j);

switch (phone_number.type())
{
case tutorial::Person::MOBILE:
cout << " Mobile phone #: ";
break;
case tutorial::Person::HOME:
cout << " Home phone #: ";
break;
case tutorial::Person::WORK:
cout << " Work phone #: ";
break;
}
cout << phone_number.number() << endl;
}
}
}

// Main function: Reads the entire address book from a file and prints all
// the information inside.
int main(int argc, char *argv[])
{
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;

int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1)
{
cerr << "Error creating socket." << endl;
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = 13157;
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
cerr << "Error binding socket." << endl;
return 1;
}
char buf[2048] = {0};
int len = strlen(buf);
std:
cout << "wait connect ..." << std::endl;
recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&addr, (socklen_t *)&len);
std::cout << "connect successfull ..." << std::endl;
tutorial::AddressBook address_book;

{
if (!address_book.ParseFromString(buf))
{
cerr << "Failed to parse address book." << endl;
return -1;
}
}

ListPeople(address_book);

// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();

return 0;
}

运行:

zxp@zxp-pc:~/zxp/proto_test/build$ ./write 
Enter person ID number: 999
Enter name: 999
Enter email address (blank for none): 999
Enter a phone number (or leave blank to finish):
zxp@zxp-pc:~/zxp/proto_test/build$
zxp@zxp-pc:~/zxp/proto_test/build$ ./read 
wait connect ...
connect successfull ...
Person ID: 999
Name: 999
E-mail address: 999
zxp@zxp-pc:~/zxp/proto_test/build$