关于erlang的多节点通信,可以默认所有集群中的节点都运行在一个被信任和可靠的网络中,连通的节点间可以直接进行内部调用。
下面通过一个简单的例子说明如何进行节点间的连接。开启2个erl节点:
erl -name node1@127.0.0.1
erl -name node2@127.0.0.1
在shell中输入
nodes().
可以看到返回值为
[]
这是因为当前无连通的节点。在shell1中执行
net_adm:ping('node2@127.0.0.1').
然后再执行
nodes().
这时看到输出结果为
['node2@127.0.0.1']
这时node1和node2已经连通。关于net_adm该模块,可以查看官网的说明文档:
http://erlang.org/doc/man/net_adm.html
为了安全性,防止别人也可以直接连上你的节点,我们一般需要加上cookie,当cookie不匹配时无法连通。下面是示例:
erl -name node1@127.0.0.1 -setcookie demo
erl -name node2@127.0.0.1 -setcookie demo
erl -name node3@127.0.0.1
启动3个shell后进行连通,可以看到node3无法加入node1或node2。
现在我们把3个节点都连通:
erl -name node1@127.0.0.1 -setcookie demo
erl -name node2@127.0.0.1 -setcookie demo -eval "net_adm:ping('node1@127.0.0.1')"
erl -name node3@127.0.0.1 -setcookie demo -eval "net_adm:ping('node1@127.0.0.1')"
可以看到,node2和node3都连向node1,但我们在node3却发现node2节点也被连上了(在node2上也发现node3也被连接上了),这是因为集群中的节点都是互通的,一个新加入的节点会跟集群中的节点都进行连通。如果不希望自动连通,我们可以把node1设为孤立节点:
erl -name node1@127.0.0.1 -setcookie demo -connect_all false
这时再重启节点,可以发现只有node1连通了node2、node3,而node2和node3只连上了node1。
连通之后,节点之间的互相调用就变成很简单了,下面有个简单的例子:
-module(t).
-behaviour(gen_server).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-export([start/1,get/0]).
start(N) ->
gen_server:start({local, ?MODULE}, ?MODULE, [N], []).
get() ->
gen_server:call(?MODULE, get).
init([N]) ->
{ok, N}.
handle_call(get, _From, Status) ->
{reply, Status, Status};
handle_call(_Event, _From, Status) ->
{reply, ok, Status}.
handle_cast(_Event, Status) ->
{noreply, Status}.
handle_info(_Event, Status) ->
{noreply, Status}.
terminate(_Reason, _Status) ->
ok.
code_change(_OldVsn, Status, _Extra) ->
{ok, Status}.
然后我们的启动命令也稍做一下修改:
erl -name node1@127.0.0.1 -setcookie demo -connect_all false -eval "t:start(1)"
erl -name node2@127.0.0.1 -setcookie demo -eval "net_adm:ping('node1@127.0.0.1'),t:start(2)"
erl -name node3@127.0.0.1 -setcookie demo -eval "net_adm:ping('node1@127.0.0.1'),t:start(3)"
这样我们在node1的shell中,执行t:get().可以看到结果是1,而执行rpc:call('node2@127.0.0.1', t, get, []).看到结果是2,执行rpc:call('node3@127.0.0.1', t, get, []).看到结果是3(当然,执行rpc:call('node1@127.0.0.1', t, get, []).看到结果是1)。