通讯使用Protobuf,还有必要的压缩卷不存在再做一遍压缩吗

2013年7月 C/C++大版内专家分月排行榜第一
2015年9月 C/C++大版内专家分月排行榜第二2013年6月 C/C++大版内专家分月排行榜第二
2013年 总版技术专家分年内排行榜第三
2012年 总版技术专家分年内排行榜第七
2013年 总版技术专家分年内排行榜第三
2012年 总版技术专家分年内排行榜第七
本帖子已过去太久远了,不再提供回复功能。在Android 开发中使用Protobuf的实践和经验分享 - 一江春水邀明月 - ITeye技术网站
博客分类:
版权所有, 如需转载请保留链接
http://wangbt5191-hotmail-/blog/1914408/
Android 下使用ProtoBuff的实践和心得。在最近的 Android 客户端项目中, 我们由于节省流量和减少序列化和反序列化运算开销的考虑, 我们选择了Protobuff 作为中间传输的序列化的工具。为了规避编译ProtobufSchema的麻烦, 我们使用第三方的开源包
来使用Runntime的Protobuf Schema.
1. 依赖引入:
&dependency&
&groupId&com.google.protobuf&/groupId&
&artifactId&protobuf-java&/artifactId&
&version&2.4.1&/version&
&/dependency&
&dependency&
&groupId&com.dyuproject.protostuff &/groupId&
&artifactId&protostuff-core&/artifactId&
&version&1.0.7&/version&
&/dependency&
&dependency&
&groupId&com.dyuproject.protostuff &/groupId&
&artifactId&protostuff-runtime&/artifactId&
&version&1.0.7&/version&
&/dependency&
2. 使用Protobuf 做对象序列化反序列化
private Charset charset = Charset.forName(&ISO-8859-1&);
P getObj(String s, Class typeClass){
Schema schema = RuntimeSchema.getSchema(typeClass);
obj = targetType.newInstance();
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
ProtostuffIOUtil.mergeFrom(Base64.decode(s.getBytes(charset), Base64.DEFAULT), obj, schema);
public String convert2String(Object o){
if(o == null || &&.equals(o)){
//TODO: consider to throw exception
Class typeClass=
o.getClass();
Schema schema = RuntimeSchema.getSchema(typeClass);
LinkedBuffer buffer = getApplicationBuffer();
byte[] protostuff = ProtostuffIOUtil.toByteArray(o, schema, buffer);
return new String(Base64.encode(protostuff, Base64.DEFAULT),charset);
buffer.clear();
private LinkedBuffer getApplicationBuffer() {
return LinkedBuffer.allocate(1024);
3. Android Dalvik JVM 实现中的坑
但是且慢, 这样的代码在Server端代码做Junit Test的时候, 和Android 本地的代码Test的时候做本地的Java 对象的序列化到字符串, 再反序列化回Object 都没有什么问题, 但是联调的时候出问题了, 无论怎么调试Android 客户端使用这个代码逻辑去反序列化都不能成功。开始我们怀疑是Http 协议传输的时候, 字符编码的问题, 并在这个上面打转了大半天的时间。 后来突然发现这个是Android JVM 实现中的一个坑。 也或者说 的没考虑到的Case。
在解释这个问题之前, 我们先看看 如何生成运行期的protobuf Schema的。 也就是RuntimeSchema.getSchema(typeClass)这里, 到底发生了什么。 它的基本流程是:
获取当前typeClass 的所有Super Class2. 对SuperClass 调用 getDeclaredFields 方法获取Field 列表, 并做一些过滤( 比如transient 修饰的字段是需要过滤的), 把这些Field 列表中field按顺序以 这样的键值对的形式放到HashMap中
3. 重复第二部, 从最根的SuperClass 一直做到当前的typeClass。4. 然后根据HashMap进行编译出protobuf 的Schema。我们发现问题出在第二步, Android 下getDeclaredFields 方法返回的Field 列表顺序和我们在类里面定义的不一样。 它是做过字母排序的。 我们知道Protobuf 的序列化中所需要的Schema 是对类下面的Field顺序强依赖的。而在我们的Server端的调式中, 我们发现我们的Field顺序是和我们在类中定义的是一样的。 上也有类似的讨论, JDK 1.6 以上这个顺序才保证是和类定义中的顺序是一致的, 而在早期版本中这个顺序是没保证的, 是根据各JDK 的实现自己做的。 也就是说
其实只能保证在JDK1.6 以上能正确运行。 更别说Android这样的非正统的JVM 系统了。问题找到了, 那怎么解决呢?
4. 定制RuntimeSchema的生成逻辑
这里要做的事情是需要把Android 的上最终push 到hashMap
中的顺序保证和Java 类中定义的顺序一样就可以了。 好吧, 这个只有借助Annotation了。
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface FieldOrder {
public int order() default 0;
我们定义个这样的Annotation, 然后改写
static void fill(Map&String,java.lang.reflect.Field& fieldMap, Class&?& typeClass)
if(Object.class!=typeClass.getSuperclass())
fill(fieldMap, typeClass.getSuperclass());
List&java.lang.reflect.Field& fieldList = new ArrayList&java.lang.reflect.Field&();
for(java.lang.reflect.Field f : typeClass.getDeclaredFields())
int mod = f.getModifiers();
if(!Modifier.isStatic(mod) && !Modifier.isTransient(mod))
fieldList.add(f);
final String className = typeClass.getName();
Collections.sort(fieldList, new parator&java.lang.reflect.Field&(){
public int compare(java.lang.reflect.Field lField, java.lang.reflect.Field rField){
if(lField.getAnnotation(FieldOrder.class) == null || rField.getAnnotation(FieldOrder.class)==null)
throw new RuntimeException("Class " + className + " " +
lField.getName() + " or " + rField.getName() + " not set order.");
return lField.getAnnotation(FieldOrder.class).order() - rField.getAnnotation(FieldOrder.class).order();
for(java.lang.reflect.Field f: fieldList){
fieldMap.put(f.getName(), f);
上面的实例代码中Collections.sort改写后添加的逻辑, 也就是根据Annotation, 在使用field 列表put 到FieldMap 之前最一次根据Annotation 定义的顺序进行一次排序。
public class SearchObject {
@FieldOrder(order = 1 ) private int currentP
@FieldOrder(order = 2 ) private int pageS
5. 反思Protobuf的应用场景
我们知道Protobuf 对兼容字段差异的兼容可以做到的是, 如果有一个Bean Class 有10个字段序列化方S方和反序列化方DS 方的字段, 假如有Bean Class 在某一边做了升级, 添加了第11 个field, 如果这第11 个field 在field 列表的末尾, 那么是没问 题的。 如果在中间添加这个字段, 那将会导致在另一边无法做反序列化。 从上面第三节里面, 我们看Protobuf的生成Protobuf Schema的流程我们知道, 假如有个类ClassA extends SuperClassA 如果ClassA 中有FieldA1, FieldA2. SuperClassA 中有FieldsSA1, FieldsSA2。 那么最终编译到Schema 中的顺序会是FieldsSA1, FieldsSA2, FieldA1, FieldA2.
如果我们对SuperClassA上新增FieldSA3, 那么顺序会是
FieldsSA1, FieldsSA2, FieldsSA2, FieldA1, FieldA2. 如果另外一端因为Class 未升级, 那么编译的顺序还是FieldsSA1, FieldsSA2, FieldA1, FieldA2. 那么将会导致无法正确反序列化。用一句话总结就是, 如果Super Class中新增字段了, 必须两端程序同时升级。 而如果在子类中新增字段, 并且增加在字段列表中的最后一个, 那么是不需要另外一端跟着升级的。这里我们可以看到protobuf 的运行高效性所带来的一些问题。 相应的这类问题是不会存在在使用Json 格式转换服务上。
最后, 相关的更改见附件
下载次数: 125
浏览 12601
那个依赖引入的xml是往哪写入?&& RuntimeSchema& 是哪的类?求源代码在pom.xml里面, 这个是maven 管理的工程
lz,这种方式貌似不行了。sorry ,我弄错了.另外@Tag实现了你说的这个功能.
一江春水邀明月
浏览: 41180 次
来自: 杭州
read_act 写道那个依赖引入的xml是往哪写入?
那个依赖引入的xml是往哪写入?
RuntimeSchem ...
aa 写道lz,这种方式貌似不行了。sorry ...
lz,这种方式貌似不行了。
有使用,比较稳定。 但是需要注意的是Orika实例不能做laz ...【图文】protobuf简介与应用_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
评价文档:
protobuf简介与应用
上传于|0|0|文档简介
&&protobuf的简单介绍使用
大小:1.34MB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢protobuf厂内通讯模块的设计的思考 - 移动互联网后端技术 - ITeye技术网站
博客分类:
一直以来比较关心高性能通讯模块的设计,最近看到两篇好文,由此想到曾经参与的几个通讯模块的设计和实现,跟大家分享思路。
首先来分享好文:
这一篇讲得是google protobuf协议和其他序列化的性能测试。朋友们看了一定会砰然心动,protobuf如此之高的通讯效率当然是求之不得。新浪微博IM各模块之间也采用protobuf作为通讯协议,TimYang写过文章比较google protobuf和facebook Thrift之间的性能。也证实了protobuf还是好东东。加之MINA可以很好的和此类通讯协议结合,无非是编解码嘛,一行伪代码搞定:
mySocketAcceptor.getFilterChain().addFirst("protobuf", new ProtocolCodecFilter(ProtobufCodecFactory.newInstance(MyProBufPacket.getDefaultInstance())));
第二篇是讲解为什么protobuf有如此效率,大家慢慢品味吧。
使用protobuf二进制协议高效的传输,在通讯压力大得场合非常合适。
私有协议,如果是基于公共协议的中间件。想推广使用,有一定阻力。
还是那句话:场景和应用决定构架,技术只是手段,客户的需求才是根本。
引用TimYang的话作为结尾
一个构架师的经验主要在于经历了多少场景,即解决了特定场景下的要求的经验
以及试错过程中积累的经验和对各种主流技术的掌握
背靠Google这棵大树,不用太担心了。protobuf自08年开源以来得到了业内积极的评价,且Google开源产品的质量向来是可信的。参考protobuf官网:/protocol-buffers/docs/overview,protobuf相比XML,速度快20到100倍,大小缩小3-10倍;因此protobuf不仅仅可以用来做数据传输,还可以用来压测存储。也可以考虑Facebook的thrift,网上有朋友测过,两者性能差不多。但因Facebook风头正劲,根据程序猿的兴趣,使用thrift也无不可。国内的案例,新浪微博大量使用了protobuf。谢谢lz的补充介绍,十分感谢!
浏览: 212651 次
来自: 北京
完全没看懂诶
楼主 为什么是1.27F 求解释
有个疑问,请教下:扩容问题之一:如果不降低命中率?如果使用为垂 ...
maoyidao 写道Yiyang说的对,不过这只是一个理论上 ...
RingBuffer怎么会涉及到GC的问题呢??LZ给的最后的 ...}

我要回帖

更多关于 protobuf通讯 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信