問題描述:
RPC(Remote Procedure Call)遠端程式呼叫:
如果要給另一個節點發資訊:可以簡單寫成:
call(Msg,Node) -> {server,Node}!{self(),Msg}, receive {ok,Res} -> Res end. server() -> register(server,self()), loop(). loop() -> receive {Pid,N} -> Pid!{ok,N*N} end, loop().
以上就是RPC的原型,但是要注意本地呼叫和遠端呼叫區別在於遠端節點可能失效,可以加個超時:
call(Msg,Node) -> {server,Node}!{self(),Msg}, receive {ok,Res} -> Res after 1000 -> {error,timeout} end.
Tip: 但是要特別注意的是:超時後仍可能收到訊息並儲存在程式郵箱中,遠端伺服器很忙或網路不佳時,如果你不重新整理訊息,下次call/2並且傳送一個新的請求時,最終你取出了是佇列的每一個訊息,就是你call(A,Node)timeout了,又call(B,Node),可能你得到的是A的結果,這個不重新整理真悲劇。
erlang把上面的原理也用gen_server封裝了下,就有了rpc:call(Node,Module,Func,Args)這個函式。
以上來源於:Erlang程式設計指南
問題:都已經可以用RPC和遠端節點通訊了,還要net_kernel來做什麼?
注意到,我們發資訊時還要指定對應的Node名字,對於呼叫者是不好的,(這個引數也不好找),Erlang要的效果是:把本地節點方式和遠端節點編寫方式統一,將其透明化。
因為只要知道PID就可以給它發資訊這個特性,可以分2步完成。
1. 把要用的節點手動連線起來,
2.使用加強版本的global:whereis_name/1代替erlang:whereis/1.
所以這就是net_kernel的作用:用於手動啟動,停止,連線和監控節點的構造。
這樣你發資訊可以這樣子!和本地是一樣了啦!!!
erlang:send(global:whereis_name(test),for_test).
Tips:
1. 這裡使用:net_kernel:connect/1成功的前提一定是cookie相同;
2. erl 可以用-connect_all_false 標記,來不讓別的節點連線,系統也不會保留連線節點的全域性表,這樣就可以阻止全域性宣告。
3. erl –hidden將節點隱藏起來:原因如果N個節點隱藏互連,就會互相監視,要保持N*(N-1)/2的連線,增加了節點凌晨傳送監控訊息的開銷,所以就把不用的節點先隱藏,要用的時候再用net_kerlel:connect(Node)建立;
4. erl –name –sname 最好不要混用;
5. nep_adm: ping(Node)可以Node有沒有連線上來pong通,pang不通.
epmd程式:如果你是在用UDP或TCP等協議來做分散式的話:
以下摘自Erlang程式設計指南:
epmd是erlang執行時系統的一部分,它為erlang分散式的節點扮演了埠對映看守程式的角色,無論多少分散式節點執行在它上面,每個機器 只會啟動一個epmd看守程式程式,監聽來自己埠4369的所有連線請求,並把綜們對映到被接節點的監聽埠,如果還沒有開始執行,當啟動你第一個分散式erlang節點時epmd會自動執行,然後通過 手動開啟,可以傳遞一系列的命令和設定引數。