erlang+thrift配合开发

I  think, thrift is a  tcp/ip based Client-Server architecture multi-languages supported RPC framework.

要使用thrift+erlang开发,要经过下面几个步骤。

 

1.对thrift了解。

thrift的功能的确是强劲,不过thrift缺少文档的确是它的硬伤,尤其是具体的语言的API文档更是缺少,网上基本上是java api的文档。下面是我收集的一些文档,对thrift的定义和使用都有具体的介绍,可以说是thrift的入门必备资料。

Thrift: The Missing Guide

有pdf文档可以下载,15页,短小精悍,我就是看了这个文档对thrift有所了解。

thrift whitepaper

thrift的白皮书,介绍了thrift的历史和使命。

Apache Thrift - 可伸缩的跨语言服务开发框架

使用java开发可以看看。

Thrift实践

介绍thrift的一些特性

Apache Thrift-quick tutorial

包括安装、使用等一系列内容。

看完这一系列文档,对thrift的定义、使用、以及特性都会有比较深入的了解,可以减少使用中遇到的问题。

 

2.thrift开发一般步骤

Erlang中使用Thrift 里面讲到了使用erlang+thrift的一般步骤:

第一步:编写相应的*.thrift  文件
第二步:thrift --gen erl *.thrift,将生成的gen-erl复制到src中
第三步:按照例子代码写一个模块,将*.thrift中的函数全都实现了,并在里面指定服务的端口号和启动thrift的框架
第四步:将上一步写的模块添加到整个程序启动过程的最末处,启动thrift开始对外提供服务。

 

3.thrift与erlang实战

首先对thrift的erlang代码有所了解,下面这个博文就是阅读代码的心得

Thrift Erlang实现源代码阅读

读了这个博文后,我们就开始thrift+erlang的开发了。

thrift+erlang的用例就有thrift源码里面的tutorial,看懂了这个示例,基本上就可以使用thrift开发erlang服务器程序。

在这里,我使用的是另外一个示例,是在网上另外一个例子:

初试thrift (自备梯子)

thrift粘合erlang (自备梯子)

定义hello.thrift文件:

service Hello{
    string say(1:string name)
}

生成erl文件:

thrift --gen erl hello.thrift

gen-erl目录里面就有我们需要的erlang代码。

#ls gen-erl/
hello_constants.hrl  hello_thrift.erl  hello_thrift.hrl  hello_types.erl  hello_types.hrl

打开hello_thrift.erl,里面就是:

%%
%% Autogenerated by Thrift Compiler (0.9.1)
%%
%% DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
%%

-module(hello_thrift).
-behaviour(thrift_service).


-include("hello_thrift.hrl").

-export([struct_info/1, function_info/2]).

struct_info('i am a dummy struct') -> undefined.
%%% interface
% say(This, Name)
function_info('say', params_type) ->
  {struct, [{1, string}]}
;
function_info('say', reply_type) ->
  string;
function_info('say', exceptions) ->
  {struct, []}
;
function_info(_Func, _Info) -> no_function.

可以看到上面定义的say方法,在hello_thrift.erl里面有say方法的参数类型、返回类型,异常等信息。

在hello.thrift里面没有定义任何类型,所以在 hello_types.erl没有任何实质内容。

从上面的例子来看,产生erlang文件的思路是根据type以及service来命名。

 

在gen-erl目录里面,新建一个hello_server2.erl文件,

-module(hello_server2).
-include("hello_thrift.hrl").
-export([start/0, handle_function/2, say/1, stop/1]).


debug(Info)->
    io:format("Debug info:~s~n",[Info]).

say(Name)->
    io:format("~n Line:~p~n", [?LINE]),
    Sentence = "Hello," ++ Name,
    debug(Sentence),
    BinSentence = list_to_binary(Sentence),
    BinSentence.

start()->
    start(9090).

start(Port)->
    Handler = ?MODULE,
    thrift_socket_server:start([{handler, Handler},
            {service, hello_thrift},
            {port, Port},
            {name, hello_server}]).

stop(Server)->
    thrift_socket_server:stop(Server).


handle_function(Function, Args) when is_atom(Function), is_tuple(Args) ->
    case Function of
        say ->
            {reply, say(tuple_to_list(Args))};
        % add function here
        _ ->
            error
    end.

如果参照这个hello_server2.erl和thrift-0.9.1/tutorial/erl/server.erl,可以发现他们的结构差不多。

一般代码的思路是,使用thrift_socket_server:start/1函数来启动服务,导出handle_function/2函数来处理RPC访问。

所以可以看出,一般的思路就是在thrift文件,里面添加需要导出的函数定义,然后在handle_function/2函数处添加额外的代码。thrift框架真的是节省了程序员的开发时间。

使用erlang来做thrift的客户端开发,也比较容易,直接上代码:

-module(hello_client).
-include("hello_thrift.hrl").
-export([test/0]).

p(X)->
    io:format("in the p() ~w~n", [X]),
    ok.

test()->
    Port = 9090,
    {ok, Client0} = thrift_client_util:new("localhost",
            Port,
            hello_thrift, []),
    io:format("~n Client0 : ~p~n", [Client0]),
    {Client1, Res} =  thrift_client:call(Client0, say, ["world"]),
    io:format(" the Res is ~p~n", [Res]),
    io:format("~n Client1 : ~p~n", [Client1]),
    p(Res),
    io:format("the Client0 == Client1: ~p~n", [Client0 == Client1]),
    thrift_client:close(Client1),
    ok.

 

效果演示图:

 

 

posted @ 2014-01-07 22:45 格通 阅读(...) 评论(...) 编辑 收藏