最近有工作需要打算为项目服务器做一个机器人,测试测试压力,根据自己的经验,使用Erlang来做是最合适不过的了,但是服务器使用的C++语言,使用了Google的ProtoBuffer作为协议进行数据交换,而Erlang并没有官方的Protobuffer版本支持,官方仅支持C++,JAVA,Python等几种比较主流的语言。在网上搜索了一下,ProtoBuffer的第三方Erlang版本主要有以下几个:

  1. https://github.com/ngerakines/erlang_protobuffs/tree/master
  2. https://github.com/basho/erlang_protobuffs
  3. http://piqi.org/
  4. https://github.com/tomas-abrahamsson/gpb

我使用了一下其中的一两个版本,但是发现有的对import的支持很有限,甚至不支持,而项目中的PB是有用到,最后选定第四个版本gpb,这个版本可以使用项目中的大部分proto文件生成Erlang源文件,仅有import引用的类型有引用前缀的时候不支持。举个例子:

假如现在有两个proto文件,A.proto和B.proto,A.proto中定义了一个枚举:

package A;

enum Type
{
T_A = 0;
T_B = 1;
}

B.proto中引用了这个枚举:

message M_Test
{
required A.T_A eType = 1;
optional int32 other = 2;
}

这个时候编译proto文件,会出现如下错误:

in msg M_Test, field eType: undefined reference  A.T_A

但是如果将B.proto中的消息定义改为:

message M_Test
{
required T_A eType = 1;
optional int32 other = 2;
}

则能够成功编译通过。

为了解决这个问题,研究了一下gpb的源码,在gpb_parse.erl中有一个函数:

%% -> {found, {msg,FullName}|{enum,FullName}} | not_found
resolve_ref(Defs, Ref, Root, FullName) ->
case is_absolute_ref(Ref) of
true ->
FullRef = ensure_path_prepended(Root, Ref),
find_typename(FullRef, Defs);
false ->
PossibleRoots = compute_roots(FullName),
find_ref_rootwards(PossibleRoots, Ref, Defs)
end.

这个函数是专门用来解析引用的,其中的变量Ref在第一种写法,其值为:['A','.','T_A'],这个时候解析不了;而第二种方式的写法其值为:['T_A']。

如果匹配一下第一种写法的值,然后将之改为第二种写法的值,即可正常编译。为此我加了一个过滤函数如下:

filterRef([_,'.',Type]) -> [Type];
filterRef(Other) -> Other.

然后把resolve_ref函数改为:

%% -> {found, {msg,FullName}|{enum,FullName}} | not_found
resolve_ref(Defs, Ref0, Root, FullName) ->
Ref = filterRef(Ref0),
case is_absolute_ref(Ref) of
true ->
FullRef = ensure_path_prepended(Root, Ref),
find_typename(FullRef, Defs);
false ->
PossibleRoots = compute_roots(FullName),
find_ref_rootwards(PossibleRoots, Ref, Defs)
end.

这样,就可以正常的编译项目中所有的Proto文件了。

btw,按gpb官方的介绍来看,其支持proto2以及proto3的语法,但不知道是否完全支持,有待验证。

Erlang使用ProtoBuffer的更多相关文章

  1. thrift与protobuffer的区别

    thrift由facebook出品,protobuffer由google出品: 下面对比一下这两个的区别.参考:http://zhidao.baidu.com/link?url=yNLBeHhWokf ...

  2. [Erlang 0129] Erlang 杂记 VI

    把之前阅读资料的时候记下的东西,整理了一下. Adding special-purpose processor support to the Erlang VM   P23 简单介绍了Erlang C ...

  3. [Erlang 0128] Term sharing in Erlang/OTP 下篇

    继续昨天的话题,昨天提到io:format对数据共享的间接影响,如果是下面两种情况恐怕更容易成为"坑", 呃,恰好我都遇到过; 如果是测试代码是下面这样,得到的结果会是怎样?猜! ...

  4. [Erlang 0127] Term sharing in Erlang/OTP 上篇

    之前,在 [Erlang 0126] 我们读过的Erlang论文 提到过下面这篇论文: On Preserving Term Sharing in the Erlang Virtual Machine ...

  5. [Erlang 0126] 我们读过的Erlang论文

    我在Erlang Resources 豆瓣小站上发起了一个征集活动 [链接] ,"[征集] 我们读过的Erlang论文",希望大家来参加.发起这样一个活动的目的是因为Erlang相 ...

  6. [Erlang 0125] Know a little Erlang opcode

    Erlang源代码编译为beam文件,代码要经过一系列的过程(见下面的简图),Core Erlang之前已经简单介绍过了Core Erlang,代码转换为Core Erlang,就容易拨开一些语法糖的 ...

  7. [Erlang 0124] Erlang Unicode 两三事 - 补遗

    最近看了Erlang User Conference 2013上patrik分享的BRING UNICODE TO ERLANG!视频,这个分享很好的梳理了Erlang Unicode相关的问题,基本 ...

  8. [Erlang 0123] Erlang EPMD

     epmd进程和Erlang节点进程如影随形,在Rabbitmq集群,Ejabberd集群,Couchbase集群产品文档中都会有相当多的内容讲epmd,epmd是什么呢?   epmd 是Erlan ...

  9. [Erlang 0122] Erlang Resources 2014年1月~6月资讯合集

    虽然忙,有些事还是要抽时间做; Erlang Resources 小站 2014年1月~6月资讯合集,方便检索.      小站地址: http://site.douban.com/204209/   ...

随机推荐

  1. python 调取 shell 命令的几种方法

    os.system()无法获得到输出和返回值 os.popen()output = os.popen('cat /proc/cpuinfo')print output.read()返回的是 file ...

  2. C# 调用CMD执行命令行

    这几天用c#做了一个项目,其中一个功能是要把生成的临时文件隐藏,同时,不能在屏幕上有调用CMD的痕迹,这里生成的临时文件的绝对路径为delfile为文件的绝对路径, 代码如下: private voi ...

  3. AspectJ基本用法

    参考:深入理解Android之AOP AOP虽然是方法论,但就好像OOP中的Java一样,一些先行者也开发了一套语言来支持AOP.目前用得比较火的就是AspectJ了,它是一种几乎和Java完全一样的 ...

  4. Java内存泄露实例

  5. 老李分享:Android -自动化埋点 1

    老李分享:Android -自动化埋点   当我们开发一款Android应用上线后,希望能收集一些用户操作的行为数据,比如用户在某个页面点击了多少次,在某个控件被点击了多少次,在某个页面停 留了多少时 ...

  6. 2.Maven 使用

    1 Maven使用 1.1 编写POM 就像Make的Makefile,Ant的build.xml一样,Maven项目的核心是pom.xml. 首先创建一个名为hello-world的文件夹(本书中各 ...

  7. 微软在.NET官网上线.NET 架构指南频道

    微软在Visual Studio 2017 正式发布的时候也上线了一个参考应用https://github.com/dotnet/eShopOnContainers , 最近微软给这个参考应用写了完善 ...

  8. Mongodb Geo2d索引原理

    作者:孔德雨 MongoDB的geo索引是其一大特色,本文从原理层面讲述geo索引中的2d索引的实现. 2d 索引的创建与使用 通过 db.coll.createIndex({"lag&qu ...

  9. Ubuntu 12.4 server 安装 redmine

    1,安装默认的redmine apt-get install apache2 libapache2-mod-passenger mysql-server redmine redmine-mysql 直 ...

  10. jquery template.js前端模板引擎

    作为现代应用,ajax的大量使用,使得前端工程师们日常的开发少不了拼装模板,渲染模板 在刚有web的时候,前端与后端的交互,非常直白,浏览器端发出URL,后端返回一张拼好了的HTML串.浏览器对其进行 ...