银行业务示例
这一节我们将展示如何结合BIF monitor_node/2和向远程节点的注册进程发送消息的能力。我们将实现一个非常简单的银行服务,用以处理远程站点的请求,比如ATM机上存款、取款业务。
程序6.1
- -module(bank_server).
- -export([start/0, server/1]).
- start() ->
- register(bank_server, spawn(bank_server, server, [[]])).
- server(Data) ->
- receive
- {From, {deposit, Who, Amount}} ->
- From ! {bank_server, ok},
- server(deposit(Who, Amount, Data));
- {From, {ask, Who}} ->
- From ! {bank_server, lookup(Who, Data)},
- server(Data);
- {From, {withdraw, Who, Amount}} ->
- case lookup(Who, Data) of
- undefined ->
- From ! {bank_server, no},
- server(Data);
- Balance when Balance > Amount ->
- From ! {bank_server, ok},
- server(deposit(Who, -Amount, Data));
- _ ->
- From ! {bank_server, no},
- server(Data)
- end
- end.
- lookup(Who, [{Who, Value}|_]) -> Value;
- lookup(Who, [_|T]) -> lookup(Who, T);
- lookup(_, _) -> undefined.
- deposit(Who, X, [{Who, Balance}|T]) ->
- [{Who, Balance+X}|T];
- deposit(Who, X, [H|T]) ->
- [H|deposit(Who, X, T)];
- deposit(Who, X, []) ->
- [{Who, X}].
程序6.1的代码运行于银行总部。而在出纳机(或分行)中执行的是程序6.2,该程序完成与总行服务器的交互。
程序6.2
- -module(bank_client).
- -export([ask/1, deposit/2, withdraw/2]).
- head_office() -> 'bank@super.eua.ericsson.se'.
- ask(Who) -> call_bank({ask, Who}).
- deposit(Who, Amount) -> call_bank({deposit, Who, Amount}).
- withdraw(Who, Amount) -> call_bank({withdraw, Who, Amount}).
- call_bank(Msg) ->
- Headoffice = head_office(),
- monitor_node(Headoffice, true),
- {bank_server, Headoffice} ! {self(), Msg},
- receive
- {bank_server, Reply} ->
- monitor_node(Headoffice, false),
- Reply;
- {nodedown, Headoffice} ->
- no
- end.
客户端程序定义了三个访问总行服务器的接口函数:
ask(Who)deposit(Who,Amount)返回客户Who的余额
withdraw(Who,Amount)给客户Who的帐户里面存入资金数Amount
尝试从客户Who的帐户里面取出资金数Amount
函数call_bank/1实现了远程过程调用。一旦总行节点停止运作,call_bank/1将会及时发现,并返回no。
总行节点的名称是硬编码在源码中的。在后续章节中我们将展示集中隐藏该信息的手段。