protobuf vs2015编译 和 示例学习笔记

此文作为protobuf 学习笔记!

Window移植

1.   环境准备

windows 7 X64;

VS2015社区版;[VisualStudio](https://www.visualstudio.com)    path增加值 C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin  

cmake - [CMake](http://www.cmake.org);    设置环境变量 ,安装时勾上。

 

2.   下载源码

   https://github.com/google/protobuf/releases  妈的,墙真是牛逼,下了三天,开了VPN都不行。下载3.0.0版,protobuf-3.0.0.zip,以及 protoc-3.0.0-win32.zip

 

3.   解压文件

源代码路径D:\cpp\protobuf-3.0.0  

生成工具路径D:\cpp\protoc-3.0.0-win32  环境变量path增加值D:\cpp\protoc-3.0.0-win32\bin

 

4.   编译

D:\cpp\protobuf-3.0.0 下 mkdir cmakebuild & cd cmakebuild (备注 build 目录没法建立,说是已经存在但是打不开);

继续D:\cpp\protobuf-3.0.0\cmakebuild 下 mkdir release & cd release; 建立工程目录

     因为是为了生成sln工程,具体要出debug还是Release 库可以在工程中配置 所以不用指定-DCMAKE_BUILD_TYPE=Release ,cmake命令如下

     D:\cpp\protobuf-3.0.0\cmakebuild/release> cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_INSTALL_PREFIX=../../../../D:\cpp\protobuf-3.0.0-install../..cmake

     可以看到当前目录下出现protobuf.sln,打开编译,注意指定架构 x64 x86,版本debug还是Release;生成后的库复制到protobuf-3.0.0-install(该目录作为工程以后用到库的路径);

     编译时提示找不到pthread.h,但是也能编译过。

<!--其他人出的问题:

      按照提示打开CMakeError.log,看到提示:无法打开包括文件: “pthread.h”,额,好吧,windows下没有pthread库,下载之~ https://sourceware.org/pthreads-win32/#download,我下载的是 pthreads-w32-2-9-1-release(官网下载可能比较慢,可以选择其中的镜像进行下载)
       后面想到当时命令行并没有添加include path的选项,所以即使使用了pthread也不太好配置(后面尝试了多种方式),后面又仔细看了下命令行输出(之前没太注意看命令行输出,只是直接看error文件,额 还是要仔细看看输出的~~),发现cmake终止是由于没有gmock。再看README中写到:

If the gmock directory does not exist, and you do not want tobuild protobuf unit tests,
you need to add cmake command argument -Dprotobuf_BUILD_TESTS=OFF to disabletesting.

       好吧,我不用测试,遂在命令行中加入-Dprotobuf_BUILD_TESTS=OFF。OK,居然过了。

-->

 

5.   测试

5.1.  定义协议格式

新建协议格式文件addressbook.proto

packagetutorial;  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;
}

该结构与c++或java很像.

 

.proto文件以包声明开始,防止名字冲突。

简单类型:bool, int32,float, double, string.

其它类型:如上述的Person,PhoneNumber

 

类型可以嵌套。

“=1”, “=2”标识唯一“tag”.tag数1-15需要至少一个字节。

 

required: 必须设置它的值

optional: 可以设置,也可以不设置它的值

repeated: 可以认为是动态分配的数组

google工程师认为使用required威害更大, 他们更喜欢使用optional, repeated.

5.2.  编译你的协议

 

运行protoc 来生成c++文件:

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

生成的文件为:

addressbook.pb.h, 

addressbook.pb.cc

5.3.  protobuf API

 

生成的文件中有如下方法:

//name
 
inlinebool has_name()const;
 
inlinevoid clear_name();
 
inlineconst::std::string& name()const;
 
inlinevoid set_name(const::std::string& value);
 
inlinevoid set_name(constchar* value);
 
inline::std::string* mutable_name();

 
// id
 
inlinebool has_id()const;
 
inlinevoid clear_id();
 
inline int32_t id()const;
 
inlinevoid set_id(int32_t value);

 
// email
 
inlinebool has_email()const;
 
inlinevoid clear_email();
 
inlineconst::std::string& email()const;
 
inlinevoid set_email(const::std::string& value);
 
inlinevoid set_email(constchar* value);
 
inline::std::string* mutable_email();

 
// phone
 
inlineint phone_size()const;
 
inlinevoid clear_phone();
 
inlineconst::google::protobuf::RepeatedPtrField<::tutorial::Person_PhoneNumber>& phone()const;
 
inline::google::protobuf::RepeatedPtrField<::tutorial::Person_PhoneNumber>* mutable_phone();
 
inlineconst::tutorial::Person_PhoneNumber& phone(int index)const;
 
inline::tutorial::Person_PhoneNumber* mutable_phone(int index);
 
inline::tutorial::Person_PhoneNumber* add_phone();

 

5.4.  Vs2015新建控制台工程

5.4.1.   测试工程1

包含目录增加 D:\cpp\protobuf-3.0.0\src;

库路径增加:D:\cpp\protobuf-3.0.0-install;

复制生成的文件addressbook.pb.h, addressbook.pb.cc到工程目录下,工程增加该文件,对addressbook.pb.cc设置属性,不处理预编译头。

 

编译测试代码:

// protobuf_002.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;
#ifndef _DEBUG 
#pragma comment(lib,"libprotobuf.lib") 
#pragma comment(lib,"libprotoc.lib") 
#else
#pragma comment(lib,"libprotobufd.lib") 
#pragma comment(lib,"libprotocd.lib") 
#endif
// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Personperson) 
{
    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(cinemail);
    if (!email.empty()) {
        person->set_email(email);
    }
    while (true) {
        cout << "Enter a phone number (or leave blank to finish): ";
        string number;
        getline(cinnumber);
        if (number.empty()) {
            break;
        }
        tutorial::Person::PhoneNumberphone_number = person->add_phone();
        phone_number->set_number(number);
        cout << "Is this a mobile, home, or work phone? ";
        string type;
        getline(cintype);
        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;
        }
    }
}
//Iterates though all people in the AddressBook and prints info about them.
void ListPeople(const tutorial::AddressBookaddress_book) 
{
    for (int i = 0; i < address_book.person_size()i++) {
        const tutorial::Personperson = 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::PhoneNumberphone_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;
        }
    }
}
int MyWrite(char** argv)
{
    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();
}
int MyRead(char** argv)
{
    tutorial::AddressBook address_book;
    {
        // Read the existing address book.
        fstream input(argv[1]ios::in | ios::binary);
        if (!address_book.ParseFromIstream(&input)) {
            cerr << "Failedto parse address book." << endl;
            return -1;
        }
    }
    ListPeople(address_book);
    //Optional:  Delete all global objects allocated by libprotobuf.
    google::protobuf::ShutdownProtobufLibrary();
}
// 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 argccharargv[]) {
    // 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 != 3) {
        cerr << "Usage:  " << argv[0] << " ADDRESS_BOOK_FILE" << "w|r" << endl;
        return -1;
    }
    if (argv[2][0] == 'w') {
        MyWrite(argv);
    }
    else if (argv[2][0] == 'r') {
        MyRead(argv);
    }
    system("pause");
    getchar();
    system("pause");
    return 0;
}

 

 

Linux移植

1.   Linux移植

在网站http://code.google.com/p/protobuf/downloads/list上可以下载 Protobuf 的源代码。然后解压编译安装便可以使用它了。

安装步骤如下所示:

 tar -xzf protobuf-2.1.0.tar.gz

 cd protobuf-2.1.0

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

 make

 make check

 make install

 

到此步还没有安装完毕,在/etc/profile 或者用户目录 ~/.bash_profile
添加下面内容
 
####### add protobuf lib path ########
#(动态库搜索路径) 程序加载运行期间查找动态链接库时指定除了系统默认路径之外的其他路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/protobuf/lib/
#(静态库搜索路径) 程序编译期间查找动态链接库时指定查找共享库的路径
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/protobuf/lib/
#执行程序搜索路径
export PATH=$PATH:/usr/local/protobuf/bin/
#c程序头文件搜索路径
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/local/protobuf/include/
#c++程序头文件搜索路径
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/local/protobuf/include/
#pkg-config 路径
export PKG_CONFIG_PATH=/usr/local/protobuf/lib/pkgconfig/
######################################

 

注意添加后重新ssh登陆才生效

 

 

创建文件/etc/ld.so.conf.d/libprotobuf.conf 写入内容:/usr/local/protobuf/lib
输入命令 sudo ldconfig

有可能提示 库不是符号链接,使用ln命令修改

ln -sflibprotobuf.so.10.0.0 libprotobuf.so.10

ln -sflibprotobuf.so.10 libprotobuf.so

 

安装后,输入protoc--version 验证是否安装成功。

 

2.   测试

 

1,people.proto

 

    package demo; 

     

    message People { 

      required string name = 1; 

      required int32 id = 2; 

      required string email = 3; 

    } 

 

 

 

2, 生成stub类

 

    protoc --cpp_out=. people.proto 

    rprotoc people.proto 

 

 

 

3, C++服务器端server.cc

 

    #include <stdio.h> 

    #include <stdlib.h> 

    #include <strings.h> 

    #include <unistd.h> 

    #include <sys/types.h> 

    #include <sys/socket.h> 

    #include <netinet/in.h> 

    #include <arpa/inet.h> 

    #include <string> 

    #include <iostream> 

    #include "people.pb.h" 

     

    #define PORT 8888 

    #define MAXDATASIZE 20 

    #define BACKLOG 10 

     

    using namespace std; 

     

    int main() 

    { 

      int listenfd, connectfd, numbytes; 

      char buf[MAXDATASIZE]; 

      struct sockaddr_in server; 

      struct sockaddr_in client; 

      int sin_size;  

     

      listenfd = socket(AF_INET, SOCK_STREAM,0); 

     

      int opt = SO_REUSEADDR; 

      setsockopt(listenfd, SOL_SOCKET,SO_REUSEADDR, &opt, sizeof(opt)); 

     

      bzero(&server, sizeof(server)); 

      server.sin_family = AF_INET; 

      server.sin_port = htons(PORT); 

      server.sin_addr.s_addr =htonl(INADDR_ANY); 

     

      bind(listenfd, (struct sockaddr*)&server, sizeof(struct sockaddr)); 

     

      listen(listenfd,BACKLOG); 

     

      while(1){ 

       sin_size = sizeof(struct sockaddr_in); 

     

        connectfd = accept(listenfd, (structsockaddr *)&client, (socklen_t*)&sin_size); 

     

        numbytes = recv(connectfd, buf,MAXDATASIZE, 0); 

        buf[numbytes] = '\0'; 

        string a = buf; 

        cout << "You got a messagefrom " << inet_ntoa(client.sin_addr) << endl; 

        cout << "Client Message:" << a << endl; 

        if(a == "GET PEOPLE") { 

          string data; 

          demo::People p; 

          p.set_name("Hideto"); 

          p.set_id(123); 

         p.set_email("hideto.bj@gmail.com"); 

          p.SerializeToString(&data); 

          char bts[data.length()]; 

          strcpy(bts, data.c_str()); 

          send(connectfd, bts, sizeof(bts),0); 

        }else { 

          send(connectfd, "Fuckingclient!\n", 16, 0); 

        } 

        close(connectfd); 

      } 

     

      close(listenfd); 

      return 0; 

    } 

 

 

 

4, C++客户端client.cc

 

    #include <stdio.h> 

    #include <unistd.h> 

    #include <strings.h> 

    #include <stdlib.h> 

    #include <sys/types.h> 

    #include <sys/socket.h> 

    #include <netinet/in.h> 

    #include <netdb.h> 

    #include <string> 

    #include <iostream> 

    #include "people.pb.h" 

     

    #define HOST "localhost" 

    #define PORT 8888 

    #define MAXDATASIZE 100 

     

    using namespace std; 

     

    int main(int argc, char ** argv) 

    { 

      int fd, numbytes; 

      char buf[MAXDATASIZE]; 

      struct hostent *he;  

      struct sockaddr_in server; 

       

      if (argc != 2) { 

        printf("Usage: %s\"COMMAND\"\n",argv[0]); 

        exit(0); 

      }  

       

      he = gethostbyname(HOST); 

      fd = socket(AF_INET, SOCK_STREAM,0); 

      bzero(&server, sizeof(server)); 

      server.sin_family = AF_INET; 

      server.sin_port = htons(PORT); 

      server.sin_addr = *((struct in_addr*)he->h_addr); 

     

      connect(fd, (struct sockaddr*)&server, sizeof(struct sockaddr)); 

     

      send(fd, argv[1], 20, 0); 

     

      numbytes = recv(fd, buf, MAXDATASIZE,0); 

      buf[numbytes] = '\0'; 

      string data = buf; 

      demo::People p; 

      p.ParseFromString(data); 

      cout << "People: "<< endl; 

      cout << "Name: " <<p.name() << endl; 

      cout << "ID: " <<p.id() << endl; 

      cout << "Email: "<< p.email() << endl; 

     

      close(fd); 

      return 0; 

    } 

 

 

5, 使用g++编译

 

    $ g++ server.cc people.pb.cc -o s-lprotobuf 

    $ g++ client.cc people.pb.cc -o c-lprotobuf 

 

 

 

6, 运行

 

        #启动server 

        ./s 

         

        You got a message from 127.0.0.1 

        Client Message: GET PEOPLE 

        You got a message from 127.0.0.1 

        Client Message: GET PEOPLE 

         

        #运行c++的client 

        ./c "GET PEOPLE" 

         

        People: 

        Name: Hideto 

        ID: 123 

        Email: hideto.bj@gmail.com 

 

 




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值