我们将展示如何结合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.