• 银行业务示例

    银行业务示例

    这一节我们将展示如何结合BIF monitor_node/2和向远程节点的注册进程发送消息的能力。我们将实现一个非常简单的银行服务,用以处理远程站点的请求,比如ATM机上存款、取款业务。

    程序6.1

    1. -module(bank_server).
    2. -export([start/0, server/1]).
    3.  
    4. start() ->
    5. register(bank_server, spawn(bank_server, server, [[]])).
    6.  
    7. server(Data) ->
    8. receive
    9. {From, {deposit, Who, Amount}} ->
    10. From ! {bank_server, ok},
    11. server(deposit(Who, Amount, Data));
    12. {From, {ask, Who}} ->
    13. From ! {bank_server, lookup(Who, Data)},
    14. server(Data);
    15. {From, {withdraw, Who, Amount}} ->
    16. case lookup(Who, Data) of
    17. undefined ->
    18. From ! {bank_server, no},
    19. server(Data);
    20. Balance when Balance > Amount ->
    21. From ! {bank_server, ok},
    22. server(deposit(Who, -Amount, Data));
    23. _ ->
    24. From ! {bank_server, no},
    25. server(Data)
    26. end
    27. end.
    28.  
    29. lookup(Who, [{Who, Value}|_]) -> Value;
    30. lookup(Who, [_|T]) -> lookup(Who, T);
    31. lookup(_, _) -> undefined.
    32.  
    33. deposit(Who, X, [{Who, Balance}|T]) ->
    34. [{Who, Balance+X}|T];
    35. deposit(Who, X, [H|T]) ->
    36. [H|deposit(Who, X, T)];
    37. deposit(Who, X, []) ->
    38. [{Who, X}].

    程序6.1的代码运行于银行总部。而在出纳机(或分行)中执行的是程序6.2,该程序完成与总行服务器的交互。

    程序6.2

    1. -module(bank_client).
    2. -export([ask/1, deposit/2, withdraw/2]).
    3.  
    4. head_office() -> 'bank@super.eua.ericsson.se'.
    5.  
    6. ask(Who) -> call_bank({ask, Who}).
    7. deposit(Who, Amount) -> call_bank({deposit, Who, Amount}).
    8. withdraw(Who, Amount) -> call_bank({withdraw, Who, Amount}).
    9. call_bank(Msg) ->
    10. Headoffice = head_office(),
    11. monitor_node(Headoffice, true),
    12. {bank_server, Headoffice} ! {self(), Msg},
    13. receive
    14. {bank_server, Reply} ->
    15. monitor_node(Headoffice, false),
    16. Reply;
    17. {nodedown, Headoffice} ->
    18. no
    19. end.

    客户端程序定义了三个访问总行服务器的接口函数:

    ask(Who)
    返回客户Who的余额
    deposit(Who,Amount)
    给客户Who的帐户里面存入资金数Amount
    withdraw(Who,Amount)
    尝试从客户Who的帐户里面取出资金数Amount

    函数call_bank/1实现了远程过程调用。一旦总行节点停止运作,call_bank/1将会及时发现,并返回no

    总行节点的名称是硬编码在源码中的。在后续章节中我们将展示集中隐藏该信息的手段。