以下三点是编写gen_server回调模块的简要步骤:
(1) 确定回调模块名。
(2) 编写接口函数。
(3) 在回调模块里编写六个必需的回调函数。
我们将制作一个简单的支付系统。把这个模块称为my_bank(我的银行)
我们将定义五个接口方法,它们都在my_bank模块里。
1.start() 打开银行
2.stop() 关闭银行。
3.new_account(Who) 创建一个新账户。
4.deposit(Who, Amount) 把钱存入银行。
5.withdraw(Who, Amount) 把钱取出来(如果有结余的话)。
每个函数都正好对应一个gen_server方法调用,代码如下:
start() -> gen_server:start_link({local, ?SERVER}, ?MPDULE, [], []).
stop() -> gen_server:call(?MPDULE, stop).
new_account(who) -> gen_server:call(?MPDULE, {new, who}).
deposit(who, Amount) -> gen_server:call(?MPDULE, {add, who, Amount}).
withdraw(who, Amount) -> gen_server:call(?MPDULE, {remove, who, Amount}).
回调模块必须导出六个回调方法:
init/1、handle_call/3、handle_cast/2、 handle_info/2、terminate/2和code_change/3。
%% gen_server 迷你模板
-behaviour(gen_server).
-export([start_link/0]).
%% gen_server回调击数
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
init([State]) -> {ok, State}.
handle_call(_Request, _From, State) ->
(reply, Reply, State).
handle_cast(_Msg, state) -> {noreply, state}.
handle_info(_Info, State) -> {noreply, State}.
terminate(_Reason, _State) -> ok.
code_change(_OldVsn, State, Extra) -> {ok, State}.
这个模板包含了一套简单的框架,可以填充它们来制作服务器。如果忘记定义合适的回调函数,编译器就会根据关键字-behaviour来生成警告或错误消息。start_link()函数里的服务器名(宏?SERVER)需要进行定义,默认是没有定义的
填写模板并稍加改动之后,就形成了以下代码:
%% API
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
init([]) -> {ok, ets:new(?MODULE, [])}.
handle_call({new, Who}, _From, Tab) ->
Reply = case ets:lookup(Tab, who) of
[] -> ets:insert(Tab, {who, 0}),
{welcome, whot};
[_] -> {Who, you_already_are_a_customer}
end,
{reply, Reply, Tab};
handle_call({add, Who, X}, _From, Tab) ->
Reply = case ets:lookup(Tab, Who) of
[] -> not_a_customer;
[{Who, Balance}] ->
NewBalance = Balance + X,
ets:insert(Tab, {Who, NewBalance}),
{thanks, Who, your_balance_is, NewBalance}
end,
{reply, Reply, Tab};
handle_call({remove, Who, X}, _From, Tab) ->
Reply = case ets:lookup(Tab, who) of
[] -> not_a_customer;
[{Who, Balance}] when X =< Balance -> NewBalance = Balance - X,
ets:insert(Tab, {who, NewBalance}),
{thanks, Who, your_balance_is, NewBalance};
[{who, Balance}] ->
{sorry, Who, you_only_have, Balance, in_the_bank}
end,
{reply, Reply, Tab};
handle_call(stop, _From, Tab) ->
{stop, normal, stopped, Tab}.
handle_cast(_Msg, State) -> {noreply,
State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) -> ok.
code_change(_0ldVsn, State, _Extra) ->
{ok, State}.
调用gen_server:start_link(Name, CallBackMod, StartArgs, Opts)来启动服务器, 之后第一个被调用的回调模块方法是Mod:init(StartArgs),它必须返回{ok, State}。
State的值作为handle_call的第三个参数重新出现。
handle_call(stop, From, Tab)返回{stop, normal, stopped, Tab},它会停止服务器。
第二个参数(normal)被用作my_bank:terminate/2的首 个参数。第三个参数(stopped)会成为my_bank:stop()的返回值