OTP(open telecomplatform),它的设计目标是用于做一套容错系统。最核心的概念就是behavior。类似类继承,在类里编写函数实现;而外层非应用逻辑相关的东西(热更新,监控机制等等)交OTP体系来控制。
先介绍gen_server模块。使用这个编写服务器只需要确认这3件事情:
1. 确定一个回调模块的名称;
2. 写接口函数;
3. 在回调模块中写需要的6个函数;
下面这个例子代码摘自《Erlang程序设计》16章。
代码:
%%
%% Author: erlang.hell
%% Date: 2012-11-18
%%
-module(my_bank).
-behavior(gen_server).
-export([start/0,stop/0,new_account/1,deposit/2,withdraw/2,
init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
%%====================================================================
%% server interface function
%%====================================================================
start()->
gen_server:start_link({local,?MODULE}, ?MODULE,[],[]).
stop()->
gen_server:call(?MODULE,stop).
new_account(Who)->
gen_server:call(?MODULE,{new,Who}).
deposit(Who,Amount)->
gen_server:call(?MODULE,{add,Who,Amount}).
withdraw(Who,Amount)->
gen_server:call(?MODULE,{remove,Who,Amount}).
%%====================================================================
%% gen_server callbacks
%%====================================================================
init([]) ->
Init=ets:new(?MODULE,[]),
io:format("init ~p ~p",[Init,?MODULE]),
{ok, Init}.
handle_call({new,Who}, _From, State) ->
Reply = case ets:lookup(State,Who) of
[]->ets:insert(State,{Who,0}),
{welcome,Who};
[_]->{exsits,Who,you_already_are_a_customer}
end,
{reply, Reply, State};
handle_call({add,Who,Amount},_From,State)->
Reply = case ets:lookup(State,Who) of
[]->not_a_customer;
[{Who,Balance}]->
NewBalance=Balance+Amount,
ets:insert(State,{Who,NewBalance}),
{thanks,Who,you_balance_is,NewBalance}
end,
{reply, Reply, State};
handle_call({remove,Who,Amount},_From,State)->
Reply = case ets:lookup(State,Who) of
[]->not_a_customer;
[{Who,Balance}] when Amount =< Balance ->
NewBalance=Balance-Amount,
ets:insert(State,{Who,NewBalance}),
{thanks,Who,your_balance_is,NewBalance};
[{Who,Balance}]->
{sorry,Who,you_only_have,Balance,in_the_bank}
end,
{reply, Reply, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
io:format("is terminate.",[]),
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
测试:
Eshell V5.9.1 (abort with ^G)
9>my_bank:new_account("erlang").
{welcome,"erlang"}
10>my_bank:deposit("erlang",10).
{thanks,"erlang",you_balance_is,10}
11>my_bank:deposit("erlang",20).
{thanks,"erlang",you_balance_is,30}
12> my_bank:withdraw("erlang",5).
{thanks,"erlang",your_balance_is,25}
遇到的麻烦:
4>my_bank:new_account("erlang",100).
** exception error: undefined functionmy_bank:new_account/2
5>my_bank:new_account("erlang").
** exception exit:{noproc,{gen_server,call,[my_bank,{new,"erlang"}]}}
in function gen_server:call/2(gen_server.erl, line 180)
6>my_bank:deposit("erlang",10).
** exception exit:{noproc,{gen_server,call,[my_bank,{add,"erlang",10}]}}
in function gen_server:call/2(gen_server.erl, line 180)
在第4步的时候,我输入了2个参数,造成异常;后面即使输入正常了,但是这个gen_server已经没有工作;这种情况下就会爆出这样的错误。{noproc,{gen_server,call,…;遇到这个问题就需要再次调用my_bank:start()函数,将server启动起来。
掌握的知识点:
1. OPT基本回调框架:
它存在6个回调函数函数,在模块起始的地方定义behavior自于gen_server;
State这个是贯穿于gen_server体系的回调函数;在每次回调都有权利修改他。Init函数用于生产出一个这样的tuple出来,handle函数用于加工;terminate的时候由于收场。
2. 基础语法:
函数覆盖的时候是使用“;”。如new,add,remove 3个方法是互为补充;我们就不能再每个函数后面写“.”。
使用cast语句来做条件分支:
cast ets:lookup( Table, Key ) of
[]->not_find;
[{ Who , Balance }] when Balance =< XXX ->
NewBalance=Balance-XXX,
ets:insert(Table,{Who,NewBalance},
{thinks};
[{Who,_}] ->
{sorry,not_enough_money}.
3. 熟悉ets相关知识:
构建一个ets出来
ets:new(?MODULE,[]).
在ets中检索
ets:lookup(TBL,KEY).
插入ets中
ets:insert(TBL,{KEY,VAL}).
佛法无边。