我们将展示如何结合BIF monitor_node/2和向远程节点的注册进程发送消息的能力。我们将实现一个非常简单的银行服务,用以处理远程站点的请求,比如ATM机上存款、取款业务。这里我用的是自己机器上的两个不同的节点,客户端为:client@wae01020199woobest.com 服务端为server@wae01020199woobest.com。两个节点分别处理客户端与服务端的逻辑。
客户端:主要封装了三个接口,ask(查询某人的存储信息),desposit(存储某人的信息,{name,money}),withdraw(取钱操作,{name,money})。这里用了monitor_node(node,true)来检查网络的连接,只要未连接上,被连接进程将向该进程发送{nodedown, nodeid},只有才第二个参数为true的时候才会进行监听,如果连接不存在,且monitor_node/2被调用,系统将尝试建立连接;若连接建立失败则投递一个nodedown消息。若针对同一节点连续两次调用monitor_node/2则在节点失败时将投递两条nodedown消息。
-module(bank_client).
-export([ask/1, deposit/2, withdraw/2]).
head_office() -> 'server@wae01020199.woobest.com'.
ask(Who) -> call_back({ask, Who}).
deposit(Who, Amount) -> call_back({deposit, Who, Amount}).
withdraw(Who, Amount) -> call_back({withdraw, Who, Amount}).
call_back(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.
服务端:首先start()方法注册一个bank_serser进程,执行server([]),此时参数为[]。在server中接受消息,ask,deposit,withdraw,例如接受ask(Who)后,返回client(From) {bank_server,lookup(Who,Data)},即为在Data中查找Who的数值。然后在client中接受后关闭监听进程,并将数据输出到控制台。在接受deposit,withdraw时处理方式类似。
-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}].
这里说明下自己创建两个节点的过程。
client:在bank_client所在目录下以管理员权限运行cmd,然后输入erl -name client。。。以client命名方式打开erlang shell。同样在bank_server中,打开cmd输入erl -name server。。。打开erlang shell。这里说一下,启动可以用 erl -name server ,也可以用erl -sname server,区别在于 The node name will be Name@Host, where Host is the fully qualified host name of the current host. For short names, use flag -sname instead.