Posts Tagged ‘Protobuf’

Protobuf 动态反射填充机制(JAVA)

星期四, 十月 23rd, 2014 708 views

利用此方案可进行自动化Protobuf的功能拓展,核心代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
com.google.protobuf.GeneratedMessage.Builder builder;
Object object;

/* 遍历protobuf builder体 取出字段 */
for (int i = 0; i < builder.getDescriptorForType().getFields().size(); i++) {

    FieldDescriptor pf = builder.getDescriptorForType().getFields().get(i);// 获取proto字段
    Field f = object.getClass().getDeclaredField(pf.getName());// 获取同名成员变量
    Method m = object.getClass().getMethod("get" + f.getName());// 获取该成员变量的get方法
    Object value = m.invoke(object);
    builder.setField(pf, value);

}

builder.build();

明者自明,不做过多解释了,本篇到此,谢谢关注。

BeiTown
2014-10-23

Protobuf-net在Unity WebPlayer中的兼容解决方案

星期四, 五月 15th, 2014 1,489 views

由于项目需要所以使用了Unity + Protobuf。
但是问题随之而来,因为Protobuf是JIT运行时动态编译的,而Unity不支持这种运行时动态编译,同时Protobuf是基于.net2.0框架的,因此当项目发布在PC时,出现了异常:

1
2
3
4
5
6
7
8
9
10
ArgumentOutOfRangeException: Argument is out of range.

Parameter name: options
at System.Text.RegularExpressions.Regex.validate_options (RegexOptions options) [0x0003a] in /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/System/System.Text.RegularExpressions/Regex.cs:248

at System.Text.RegularExpressions.Regex..ctor (System.String pattern, RegexOptions options) [0x00017] in /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/System/System.Text.RegularExpressions/Regex.cs:214

at Google.ProtocolBuffers.Descriptors.DescriptorPool..cctor () [0x00000] in :0
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for Google.ProtocolBuffers.Descriptors.DescriptorPool
......

这里使用的是Protobuf-Csharp包,通过排查,在发布时将PlayerSetting中Api Compatibility Level 设置成.Net 2.0即可解决。

如图

但当需要发布到WebPlayer的时候,发现一个基本无解的问题——WebPlayer PlayerSetting中的Api Compatibility Level按钮是灰色的!只支持.Net 2.0 subset模式,因此发布后依然无法解决protobuf异常问题。
(更多…)

Protobuf在Java中的简单实例

星期日, 五月 11th, 2014 250 views

关于protobuf的介绍请大家自行查看https://code.google.com/p/protobuf/,本篇直奔主题——如何实现一个最简protobuf的Demo

①定义协议格式
首先定义.proto文件,可参考https://developers.google.com/protocol-buffers/docs/proto

大体格式如下:

1
2
3
4
5
package com.beitown.net.msg;//包名
message TestMsg {
    required int64 Id=1;
    required string Name=2;
}

每个字段后标记的“=1”、“=2”,是在二进制编码时使用的每个字段的唯一标识。在编码时,数字1~15要比大于它们的数字少一个字节,因此,作为一个优化选项,可以把1~15的数字用于常用的或重复性的元素。
将其保存为test.proto文件

②编译ProtocolBuffer
运行ProtocolBuffer编译器protoc来生成与.proto文件相关的类
首先我们已经有了一个protoc.exe文件(生成方式不再赘述,需要的可自行查找)
官方给出的编译语句为 protoc -I=$SRC_DIR –java_out=$DST_DIR $SRC_DIR/test.proto
打开cmd命令行窗口,先cd到protoc.exe所在文件夹为根文件夹,此时输出的java源码在根文件夹下的src子文件夹中,test.proto文件在proto子文件夹中,因此命令如下

1
protoc --java_out=src proto/test.proto

若出现提示 Expected top-level statement (e.g. “message”) 为编码格式问题,(win7下)解决方法是使用记事本打开后另存为ANSI格式。
编译通过后会在目标文件夹即可 src/com/beitown/net/msg 下生成一个Test.java文件,我们可以对这个类的操作来实现protobuf内容的读取和写入。

③创建Message实例-序列化
接下来将说明如何对上文中的Test类进行操作,上文中定义了TestMsg这个结构体,因此创建代码如下

1
2
3
TestMsg msg = TestMsg.newBuilder().setId(001).setName("beitown").build();
msg.toByteArray();
//发送msg.toByteArray()字节流

这里的setID,setName即为protoc自动生成Test.java中自带的方法。以上即可看出对于自定数据结构我们已经无需再去关心其从二进制转为消息类的过程,即将开发从通信层剥离出来,程序只需要关心消息类的处理逻辑。

③读取Message实例-反序列化

1
2
3
4
5
//接收到字节流
byte[] data = 二进制流对象转换的字节数组;
TestMsg msg = TestMsg.parseFrom(data);
int id = msg.getId();
String name =  msg.getName();

以上即为一个protobuf在java中的简单运用实例,通过对字节数组的发送和接收来实现protobuf消息的通信。
本篇针对初次接触protobuf的朋友做为学习参考之用,更多高级应用请自行举一反三。
本篇到此,谢谢关注。

BeiTown
2014-05-11