c++ java通信 protocol buffer,google protocol buffer (C++,Java序列化应用实例)
google protocol buffer (C++,Java序列化使用實例)
轉載,請注明出處:?http://blog.csdn.net/eclipser1987/article/details/8525383 ?(eclipser@163.com)
1.下載安裝:
google protocol buffer?的官網地址是:http://code.google.com/p/protobuf/
建議下載穩定版本:protobuf-2.4.1 ?linux下載protobuf-2.4.1.tar.bz2 ? windows下載protobuf-2.4.1.zip
這里以linux下安裝為實例:
tar -xvf?protobuf-2.4.1.tar.bz2
cd?protobuf-2.4.1
./configure --prefix=/usr/local/protobuf-2.4.1
make
make install
2.使用protobuf
查看編譯生成的目錄
cd /usr/local/protobuf-2.4.1
ls
bin ?include ?lib
其中,bin中的protoc是.proto文件的處理器,可用這個工具生成cpp,java,python文件.
由于系統常用這個工具,可以將其ln或者直接拷貝到系統環境bin下
ln -s?/usr/local/protobuf-2.4.1/bin/protoc /usr/bin/protoc
同樣,可以將頭文件ln或者直接拷貝到系統環境
ln -s?/usr/local/protobuf-2.4.1/include/google /usr/include/google
將lib文件ln或者直接拷貝到系統環境
略,方法同上.
這個時候,protobuf的開發環境已經搭建了.
3.如何使用protobuf
數據結構體:
message message_name{message_body;}
message_body格式:
例如required int32 query = 1[defaut=10];
形式為:rule type name = value[other_rule];
規則:
required表示必須具有該值域;
optional表示可選的值域;
repeated表示可重復的值域(即>=0);
其中requered/optional是常用rule,而repeated則不常用同時因為是歷史遺留現使用repeated int32 samples=4[packed=true];形式;
value值:
value值最小為1,是底層編碼時使用其中1-15占一位,>15則會占多位;
不同的message中的value值互不干擾,常以1開始計數。
數據類型之基本類型:
.proto Type C++ Type Java Type
double double double
float float float
int32 int32 int
int64 int64 long
uint32 uint32 int
uint64 uint64 long
sint32 int32 int
sint64 int64 long
fixed32 uint32 int
fixed64 uint64 long
sfixed32 int32 int
sfixed64 int64 long
bool bool boolean
string string String
bytes string ByteString
數據類型之復雜類型:
復雜類型主要包括:枚舉,其他message,groups等。
枚舉定義例如:enum Corpus{WEB=0;LOCAL=1}
枚舉定義在message中。
可以使用其他message作為類型來定義成員。
groups我的理解有些像C++中的union結構。
嵌套定義:
可以嵌套定義message結構,而嵌套定義的message被其他message作為成員類型時需要形式為outmessage.inmessage形式。
包結構:
定義形式:package foo.bar;
對應C++中則生成兩個命名空間foo和bar,且bar定義在foo中;
可以通過import "myproject/other_protos.proto";來引入.proto文件;
引用其他package中message時需要完整的package路徑;
Services:
主要用于RPC系統中,在.proto中定義接口;
定義形式如例子:
service SearchService {
rpc Search(SearchRequest) return (SearchResponse);
}
.proto文件編譯:
格式:
protoc -–proto_path=(.proto文件路徑) -–cpp_out=(.cc .java生成文件路徑) (.proto文件路徑)/?.proto
-–proto_path 簡化為: --I
其中可根據需要更改:cpp_out選項為java_out/python_out。
例子:
protoc -I=./ --cpp_out=./ model.proto
我們拿個例子:
建立model.proto
package cn.vicky.model.seri;
message User {
required int32 id = 1; // 主鍵,唯一
required string username = 2; // 帳號
required string password = 3; // 密碼
optional string email = 4; // 郵箱(可選)
repeated Person person = 5; // 賬戶擁有的角色(可以重復)
}
message Person {
required int32 id = 1; // 主鍵,唯一
required string name = 2; // 角色名字
repeated PhoneNumber phone = 3; // 電話號碼(可以重復)
}
// 枚舉類型
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
protoc -I=./ --cpp_out=./ model.proto
將生成對應的model.pb.h ?model.pb.cc
使用:
編寫main.cpp
/*
* File: main.cpp
* Author: Vicky.H
* Email: eclipser@163.com
*/
#include
#include
#include "model.pb.h"
/*
*
*/
int main(void) {
// 創建User對象
cn::vicky::model::seri::User u;
u.set_id(1);
u.set_username("Jack");
u.set_password("123456");
u.set_email("289997171@qq.com");
// 創建User中的一個角色
cn::vicky::model::seri::Person* _person1 = u.add_person();
_person1->set_id(1);
_person1->set_name("P1");
// 創建角色中的一個電話號碼:1
cn::vicky::model::seri::PhoneNumber* _phone1 = _person1->add_phone();
_phone1->set_number("+8613618074943");
_phone1->set_type(cn::vicky::model::seri::MOBILE);
// 創建角色中的一個電話號碼:2
cn::vicky::model::seri::PhoneNumber* _phone2 = _person1->add_phone();
_phone2->set_number("02882334717");
_phone2->set_type(cn::vicky::model::seri::WORK);
// 創建User中的一個角色
cn::vicky::model::seri::Person* _person2 = u.add_person();
_person2->set_id(2);
_person2->set_name("P2");
// 創建角色中的一個電話號碼:1
cn::vicky::model::seri::PhoneNumber* _phone3 = _person2->add_phone();
_phone3->set_number("+8613996398667");
_phone3->set_type(cn::vicky::model::seri::MOBILE);
// 創建角色中的一個電話號碼:2
cn::vicky::model::seri::PhoneNumber* _phone4 = _person2->add_phone();
_phone4->set_number("02882334717");
_phone4->set_type(cn::vicky::model::seri::WORK);
// 持久化:
// std::fstream out("User.pb", std::ios::out | std::ios::binary | std::ios::trunc);
// u.SerializeToOstream(&out);
// out.close();
// 對象化:
cn::vicky::model::seri::User u2;
std::fstream in("User.pb", std::ios::in | std::ios::binary);
if (!u2.ParseFromIstream(&in)) {
std::cerr << "Failed to parse User.pb." << std::endl;
exit(1);
}
std::cout << u2.id() << std::endl;
std::cout << u2.username() << std::endl;
std::cout << u2.password() << std::endl;
std::cout << u2.email() << std::endl;
std::cout << "---------------------------" << std::endl;
for(int i = 0;i < u2.person_size();i++) {
cn::vicky::model::seri::Person* p = u2.mutable_person(i);
std::cout << p->id() << std::endl;
std::cout << p->name() << std::endl;
for (int j = 0;j < p->phone_size();j++) {
cn::vicky::model::seri::PhoneNumber* phone = p->mutable_phone(j);
std::cout << phone->number() << std::endl;
}
std::cout << "---------------------------" << std::endl;
}
return 0;
}
需要 -lpthread -lprotobuf ? ? ? ? ?(protobuf已經被加載到了/usr/lib)
執行后,會生成:User.pb,存儲的二進制文件.可以直接打開看看.
以上,我們使用了protobuf完成c++下的對象序列化以及反序列化.這里我們要描述一下protobuf的優勢了.
那就是protobuf性能高效,他的序列化速度比java自身的序列化還快數倍,而且支持3種語言對象的轉換.以往,在C++中序列化的對象,比如用boost serialization持久化的對象,無法用java展開,即便使用jni技術,這也是非常麻煩的事.現在我們有protobuf了.
運行:?protoc -I=./ --java_out=./ model.proto 將生成對應的Java類
我們可以用Maven建立一個Java工程.需要protobuf的java依賴庫:
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
cn.vicky
google_protobuf_01_java
1.0-SNAPSHOT
jar
google_protobuf_01_java
http://maven.apache.org
UTF-8
com.google.protobuf
protobuf-java
2.4.1
編寫Test.java
package cn.vicky.model.seri;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
*
* @author Vicky.H
*/
public class Test {
public static void main(String args[]) throws FileNotFoundException, IOException {
File file = new File("User.pb");
InputStream is = new FileInputStream(file);
Model.User user = Model.User.parseFrom(is);
System.out.println(user.getId());
System.out.println(user.getUsername());
System.out.println(user.getPassword());
System.out.println(user.getEmail());
System.out.println("-------------------");
for (Model.Person person : user.getPersonList()) {
System.out.println(person.getId());
System.out.println(person.getName());
for (Model.PhoneNumber phone : person.getPhoneList()) {
System.out.println(phone.getNumber());
}
System.out.println("-------------------");
}
is.close();
}
}
運行:
1
Jack
123456
289997171@qq.com
---------------------------
1
P1
+8613618074943
02882334717
---------------------------
2
P2
+8613996398667
02882334717
---------------------------
運行 SUCCESSFUL (總時間: ?594ms)
OK.以上我們完成了probuf在C++,Java的使用.非常強力是不是!!
設計思想:
在POJO中,protobuf生成的類,處于PO狀態,而且這個生成的類,我們最好不要做任何修改或太大的修改,那么,這個時候,我們可以通過C++友元類的方式,為PO添加一個JO類.將數據結構算法分離,也就是說,PO是數據,JO放算法!!!
與數據庫的結合:
mysql oracle 可以很輕松的存儲,讀取二進制.還有一點,那就是通過這種方式,我們可以非常簡單的將C++的對象,持久化的redis之類內存數據庫了.
附:
model.proto也可以這樣定義,不過,本人認為,上面的更好,這里僅供參考,采用什么樣的方式,生成的類的結構也不太一樣.
package cn.vicky.model.seri;
message User {
required int32 id = 1; // 主鍵,唯一
required string username = 2; // 帳號
required string password = 3; // 密碼
optional string email = 4; // 郵箱(可選)
message Person {
required int32 id = 1; // 主鍵,唯一
required string name = 2; // 角色名字
// 枚舉類型
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 3; // 電話號碼(可以重復)
}
repeated Person person = 5; // 賬戶擁有的角色(可以重復)
}
總結
以上是生活随笔為你收集整理的c++ java通信 protocol buffer,google protocol buffer (C++,Java序列化应用实例)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 混合高斯模型背景建模原理
- 下一篇: 磁力计的基本工作原理