范例
当前位置:首页 > 其他范文 > 范例 > 列表页

protobuf,c,范例

小草范文网  发布于:2016-12-06  分类: 范例 手机版

篇一:Protobuf使用例子

Protobuf使用例子

1. protobuf使用整理

protobuf序列化反序列化的一种解决方案,protobuf处理成二进制数据流,相比较xml/json更加节省数据流量。

protobuf是google提出的解决方案,有比较多的互联网公司采用此种解决方案,protobuf只支持java/python/php支持语言相对比较少。

protobuf提供了protobuf-java-xx.jar工具包处理,要求开发者定义.proto文件,然后进行执行编译成对应语言版本的源文件,比如java是编译生成.java源文件。

1.1. proto文件编写

Protobuf中的proto文件编写,比如定义一个HelloWorld.proto文件 // HelloWorld.proto文件为:

// 定义生成java文件所在的包名

option java_package = "com.helloworld.protocol";

// 生成对应外部类名称

option java_outer_classname = "HelloWorldProtoc";

message HelloWorld{

// 定义必须属性,类型为int32 required int32 num=1; // 定义可选属性,类型为int64 optional int64 num2=2; // 定义可选属性,类型为string optional string info=3; // 定义为list,list里边item类型为string repeated string mobileList=4; // 定义枚举类型,设定default默认值为MALE optional SexType sexType=5[default=MALE]; // 定义一个message对象 optional HelloWorldExt extInfo=6; enum SexType{ MALE=0;// 0-男性 FEMALE=1;// 1-女性 UNKNOWN=2;// 2-未知 }

} message HelloWorldExt{ required int32 num=1; optional int64 num2=2; optional string info=3; }

1.2. 执行生成java文件

下载到protobuf生成exe文件,名称为:protoc.exe可执行文件

编写生成.java文件脚本为:gen-test.bat内容为:

protoc --java_out=./ HelloWorld.proto

pause

生成.java文件放在当前目录下的com/helloworld/protocol文件夹目录下

protobuf生成源

文件.rar

若在client端-server端开发过程中,比如客户端使用的是Android开发,则可以将生成的protocol源文件拷贝给客户端开发了。通过HelloWorldProtoc文件进行数据携带传输。

1.3. 通过socket进行通信

下载官方提供的protobuf-java.xx.jar包,然后就可以进行开发工作了,简单采用socket进行处理client端请求,server端进行应答处理。

处理过程为:

Client发出请求>>>用HelloWorldProto进行携带数据,转换成二进制数据流 Server端接收请求>>>反序列化>>>对象>>>序列化>>>传输回给客户端

代码压缩包为:

socket方式实现

数据传输例子.rar

// HelloWorldClient.java文件为:

public class HelloWorldClient {

private final static String HOST_NAME = "localhost";

private final static int PORT = 8080;

public static void main(String[] args) {

Socket socket = null;

InputStream ins = null;

OutputStream ous = null;

try {

socket = new Socket(HOST_NAME, PORT);

socket.setKeepAlive(true);

socket.setSoTimeout(10000);

ous = socket.getOutputStream();

ins = socket.getInputStream();

HelloWorld.Builder builder = HelloWorld.newBuilder(); builder.setNum(1);

builder.setNum2(2L);

HelloWorldExt.Builder extBuilder = HelloWorldExt.newBuilder();

extBuilder.setInfo("hello world ext");

extBuilder.setNum(1);

extBuilder.setNum2(2L);

builder.setExtInfo(extBuilder.build());

// 先写length长度,然后写byte[]字节数组

// 通过toByteArray方法序列化成二进制数据

byte[] bytes = builder.build().toByteArray();

int length = bytes.length;

ous.write(length);

ous.write(bytes);

ous.flush();

System.out.println("length=" + length);

System.out.println("builder="

builder.build().toString());

// 先读length长度,然后读byte[]字节数组

int readLength = ins.read();

byte[] readBytes = new byte[readLength];

ins.read(readBytes, 0, readLength);

// 这种读法导致阻塞了

// while (ins.read(readBytes) != -1) {

// System.out.println("read ing");

// }

// 通过parseFrom方法反序列为java对象

System.out.println("readLength=" + readLength);

HelloWorld helloworld = HelloWorld.parse

protobuf c 范例

From(readBytes); +

System.out.println("extInfo="

helloworld.getExtInfo().getInfo());

} catch (UnknownHostException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally {

if (socket != null) {

try {

socket.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if (ins != null) {

try {

ins.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if (ous != null) {

try {

ous.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

}

// HelloWorldServer.java文件为:

public class HelloWorldServer {

private final static int PORT = 8080;

public static void main(String[] args) {

ServerSocket server = null;

InputStream ins = null;

OutputStream ous = null;

Socket socket = null;

try {

server = new ServerSocket(PORT); +

System.out.println("server start up success");

socket = server.accept();

ins = socket.getInputStream();

ous = socket.getOutputStream();

int length = ins.read();

byte[] bytes = new byte[length];

ins.read(bytes, 0, length);

// 这种读法导致阻塞了

// while (ins.read(bytes) != -1) {

// }

HelloWorld helloworld = HelloWorld.parseFrom(bytes); System.out.println(helloworld.toString());

ous.write(length);

ous.write(bytes);

ous.flush();

System.out.println("server write success");

} catch (IOException e) {

e.printStackTrace();

} finally {

if (server != null) {

try {

server.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if (socket != null) {

try {

socket.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if (ins != null) {

try {

ins.close();

} catch (IOException e) {

e.printStackTrace();

}

}

篇二:protobuf的安装和使用

最近领导分配了一个任务,这个工程挺高端的,主要以前从没有搞过,其中里面有protobuf,以前从来没有听说过这个东西,最近在网上看了一些高人的帖子,才知道protobuf是什么云云了,我的理解是,例如我们要用C++写个什么工程,C++是面向对象的,我们要写很多类,估计都得写上上百行,上千行的代码,但是现在用这个protobuf,就可以省很多是,我们只需要写消息包,然后编译,protobuf就会根据这个消息包自动生成两个文件.cc和.h,.h这两个文件中就有很多类,供我们调用。

现在说明怎样在Ubuntu下安装protobuf。网上有人说,他用了很多版本的protobuf都没有成功,最终用的2.5.0版本才成功,于是我就直接安装了这个版本,至于其他版本成不成功,我就不知道了。首先下载protobuf源码包

在Ubuntu的终端里输入:$wget http://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz这是在官网下载,但是我等了很长时间都没有下载下来,最后我在CSDN上下载下来了 下载之后解压: $tar xvzf protobuf-2.5.0.tar.gz

进入到解压后的目录: $ cd protobuf-2.5.0

进行执行 :$./configure

在执行./configure这个命令之前最好把vim ,g++,make安装好,不然在执行./configure的时候可能会出现错误,上面三个安装的命令:$sudo apt-get install vim $sudo apt-get install g++ $sudo apt-get install make

./configure成功之后,接下来是如下几步:

$make

$make check

$make install //在执行这一步的时候,我出现了错误,错误的意思是执行的权限不够,如果是这样的话,$make install 这条命名就换成$sudo make install

下面我们要修改一下配置文件:$ vim ~/.profile

在打开的文件中,在文件末尾添加如下代码:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

然后保存退出,接下来执行: $ source ~/.profile

使刚才修改的配置文件生效,接下来执行: $protoc --version

如果上面的步骤一切顺利的话,那么就会在终端显示protobuf的版本号,如下

下面我们来测试一下,在测试之前我们最好先建立一个文件夹,例如上面的proto,接下的操作都在这个文件夹下进行。

我们先用vim创建并编辑.proto文件,例如: $ vim msg.proto

内容如下:

然后执行下面的命令: $ protoc -I=. --cpp_out=. msg.proto

执行这条命名之后,在当前目录下就会生成如下的两个文件:

这两个文件就是根据上面的那个msg.proto文件生成了,里面有类的声明和类的实现,我们可以进入这两个文件。研究一下,这里就不在说明了。然后我们就可以调用类和里面的函数实现自己的功能了,下面是两个简单的测试文件: 我们先创建: $ vim write.cc

内容如下:

然后编译write.cc,命名如下:

$ g++ msg.pb.cc write.cc -o write `pkg-config --cflags --libs protobuf` -lpthread

执行生成的write文件,命令为:

$ ./write

可看到生成的msg.pb文件,这个文件是由

output(“./msg.pb”,ios::out|ios::trunc|ios::binary)函数生成的

下面在创建一个文件:$ vim reader.cc

内容如下:

fstream

编译reader.cc文件:命令为:

$ g++ msg.pb.cc reader.cc -o reader `pkg-config --cflags --libs protobuf` -lpthread

然后执行生成的reader文件。命令如下:

./reader

在终端就会打印出:

101

Hello

上面在生成可执行文件的过程,都是我们一条一条命令的输入,我们可以写Makefile,然后执行一条make命令,就可以自动生成可执行文件,

编写Makefile文件: $ vim Makefile

内容如下:

编写完之后,执行:$make

就会自动生成可执行文件write和

reader

Protobuffer语言详解:

Defined A Message Type

message SearchRequest

{

required string query = 1;

oprional int32 page_number = 2;

optional int32 result_per_page = 3;

}

上面 SearchRequest消息定义了三个fileds,每一个fileds都包含着该filed的name和type。 Message里面的每一个field都有一个unique numbered tag(也就是那些1 2 3 4)。这些tags用来在message binary format用来标识filed序号,如果这个message一旦被使用,建议必要轻易更改。需要注意的是,如果标记是1-15,那么当标记编码成二进制流的时候他们仅占一个字节,如果标记处于16-2047,标记将会占据两个字节,所以这里建议,对于那些需要频繁传输的数据尽量把他们放在前15位,这时编码key的时候就会尽量减少key的数据的大小,那么我们也应该留一些15因内的标记,以便将来可能会添加更频繁使用的filed。

最小的标记是1,最大的是2^29-1,但是从19000到19999这些被protobuf 实现保留。

Specifying Field Rules

你必须声明你所声明的filed是如下一种:

required:在你使用该消息时必须存在这种类型的filed

optional:在你使用该消息时该中filed可以不存在,但如果存在的只能存在一种 repeated:该中类型的filed可以被重复使用任意从(包括0次),而且protobuf会保存设置的次序。

Adding more message types

在一个.proto文件中可以定义多个message。例如你想定义多个相关联的message,如下例在一个proto文件中有一个reques message和一个reponse message message SearchRequest

{

required string query = 1;

optional int32 page_number = 2;

optional int32 result_per_page = 3;

}

message SearchResponse

{

……

}

我们可以直接使用//在.proto文件中添加注释

message SearchRequest

{

required string query = 1;

optional int32 page_number = 2; //which page number do we want?

optional int32 result_per_page = 3;

}

What's Generated From Your .proto?

当我们使用protocol buffer compiler编译一个.proto文件,编译器会生成与你所选语言(由编译选项决定--Java_Out 或者--Cpp_Out)相对应的代码。例如会生成所有字段的getter/setter,向输出流序列化你的messages以及从一个输入流中解析messages

For C++,,编译器会生成一个 .h 和.cc文件, proto文件里每一个message都会对应生成一个class.

For Java,编译器会生成一个java文件.在该java文件中会有N个由messages对应生成的内部类,以及一个Builder内部类.Builder用来创建其他messages生成的类的实例

Optional Fields And Default Values

如果一个optional field已经被手动地设置过默认值,那么在解析该messages时,发现该field没有被使用,那么该field会被设置成默认值.如下例

optional int32 result_per_page = 3 [default = 10];

那么如果没有手动地被设置过默认值那么就会采用系统默认值:string->"", bool->false, numeric->0 ,enums ->enums第一个value的默认值

Enumerations

在message中,可以使用枚举。Protobuf中的枚举以name/value形式出现。例如下例:VNIVERSAL = 0可以看出其value不是field_number

你可以对一个枚举类型的filed指定默认值,但是如果你指定的的值不在枚举列表中,那么解析器会认为这个字段为不可识别的字段。

message SearchRequest {

required string query = 1;

optional int32 page_number = 2;

optional int32 result_per_page = 3 [default = 10];

enum Corpus {

UNIVERSAL = 0;

WEB = 1;

IMAGES = 2;

LOCAL = 3;

NEWS = 4;

PRODUCTS = 5;

VIDEO = 6;

}

optional Corpus corpus = 4 [default = UNIVERSAL];

}

Using Other Message Types

我们可以采用其他的message作为我们的field类型.例如在下例中我们在同一.proto文件中定义了俩个messages,然后SearchResponse中使用Result作为field的类型.

message SearchResponse {

篇三:nanopb protobuf学习笔记

step1 : 下载官方nanopb包。

1)链接:(http://koti.kapsi.fi/jpa/nanopb/)

下载时需要注意下载对应的版本,不然编译会异常。

解压 tar zxvf nanopb-0.3.5.tar.gz

step2 : 安装proto 2 .c/.h工具.

需要安装两个软件:

1:ubuntu@ubuntu:~$ sudo apt-get install protoc (这个貌似不用安装)

2:ubuntu@ubuntu:~$ sudo apt-get install python

protoc 第一个包作用 :把proto生成.pb文件;

python第二个包作用:利用官方提供的python脚本把pb文件生成可以使用的c和h文件。

step3 : 编写.proto文件

注意:最好使用linux下vi编译器编写proto文件,在其他编译环境下(如win的文本编辑器)编译的proto文件在转换成c/h文件时可能会报错,原因是由于编码格式的问题,有些编辑环境会在文件的开头有一个特殊的字符,导致不能识别。

(http://blog.csdn.net/yangtzh/article/details/45165763)

一个proto文件示例:

文件名:simple.proto

message SimpleMessage

{

required int32 lucky_number = 1;

}

step 4 :把上一步编写的proto文件生成对应的.c/.h文件。

1)proto -> pb $protoc -osimple.pb simple.proto

2)pb -> .c/h$python nanopb/generator/nanopb_generator.py simple.pb

之后就可以在当前目录下看到需要的c或者h文件,本例中为simple.pb.c 和simple.pb.h

step5: 编写用户应用程序

主要是利用pb_ostream_from_buffer( ) 和pb_encode( )两个API函数进行对数据打包(函数在pb_encoe.h中)。

利用pb_istream_from_buffer()和pb_decode()两个函数进行对数据包解析(函数在pb_encoe.h中)。

具体使用方法参考源码包中 /nanopb/example/simple/simple.c

即在编译时需要把这些相关的文件添加到工程中。

本文已影响