如何跨两个Erlang节点发送消息

时间:2014-07-21 07:06:17

标签: erlang

我的两个Erlang模块中的代码如下:

接收者:

start() ->
    PID = spawn(?MODULE, message_box, []),
    PID.

message_box() ->
    sender:start_link(),
    receive
        {From, take_this_message} ->
            From ! "ok thanks !";
        {From, fish} ->
            From ! "So long and thanks for all the fish";
        _  ->
            io:format("Received Nothing~n")
        end.

发件人:

-module(sender).

-compile(export_all).

start_link() ->
    PID = spawn_link(?MODULE, init, [self()]),
    PID.

init(PID) ->
    PID ! {self(), "Wassup!"}.

我希望接收器在调用start_link()后显示Received Nothing。 另外,如何使用shell或其他方式检查模块/进程在运行时收到的消息?

**ERROR MESSAGE:**  

=ERROR REPORT==== 21-Jul-2014::12:42:44 ===
Error in process <0.40.0> with exit value: {undef,[{sender,start_link,[],[]},{receiver,message_box,0,[{file,"receiver.erl"},{line,14}]}]}

1 个答案:

答案 0 :(得分:3)

为了能够跨2个节点交换消息,您必须首先启动2个节点(erl -sname foo,erl -sname bar)将它们关联到群集中。这可以使用net_adm:ping / 1函数来完成:net_adm:ping(foo@domain) on the bar node.应该返回你的pong。 (如果你得到剧痛,然后拼写拼写,检查2个节点是否有相同的cookie),或者net_kernel:connect(foo @ domain)应该返回ok。

然后,您可以在一个节点上启动接收器进程,并从第二个节点获取其Pid,例如rpc:call(foo@domain,erlang,processes,[]).将返回在节点foo上运行的所有进程的列表。

然后,您可以在第二个节点上运行send函数,并在shell消息队列中获取返回的消息。

这是因为send函数使用self()来给pid提供返回答案的位置,并且它在shell进程中运行(没有产生新进程)。

如果在没有更改的情况下生成函数,则返回消息将丢失,因为在发送第一条消息后进程将立即死亡。你需要修改它,例如:

-module(sender).

-compile(export_all).

init(PID,Mess) ->
    spawn(?MODULE,send_receive,[PID,Mess]).

send_receive(PID,Mess) ->
    PID ! {self(), Mess},
    R = receive
        M -> {ok,M}
    after 5000 -> {error,"no answer!"}
    end,
    io:format("~p~n",[R]).

-module (receiver).

-compile(export_all).

start() ->
    PID = spawn(?MODULE, message_box, []),
    PID.

message_box() ->
    receive
        {From, take_this_message} ->
            From ! "ok thanks !";
        {From, fish} ->
            From ! "So long and thanks for all the fish";
        _  ->
            io:format("Received Nothing~n")
        end.
shell中的

(foo@W7FRR00423L)3> receiver:start().
<0.50.0>
Received Nothing    
(foo@W7FRR00423L)4> receiver:start().
<0.53.0>
(foo@W7FRR00423L)5> receiver:start().
<0.55.0>
Received Nothing    
(foo@W7FRR00423L)6> 



(bar@W7FRR00423L)1> net_kernel:connect(foo@W7FRR00423L).
true
(bar@W7FRR00423L)2> nodes().
[foo@W7FRR00423L]
(bar@W7FRR00423L)3> rpc:call(foo@W7FRR00423L,erlang,processes,[]).
[<6075.0.0>,<6075.3.0>,<6075.6.0>,<6075.7.0>,<6075.9.0>,
 <6075.10.0>,<6075.11.0>,<6075.12.0>,<6075.13.0>,<6075.14.0>,
 <6075.15.0>,<6075.16.0>,<6075.17.0>,<6075.18.0>,<6075.19.0>,
 <6075.20.0>,<6075.21.0>,<6075.22.0>,<6075.23.0>,<6075.24.0>,
 <6075.25.0>,<6075.26.0>,<6075.27.0>,<6075.28.0>,<6075.29.0>,
 <6075.30.0>,<6075.31.0>,<6075.32.0>,<6075.33.0>|...]
(bar@W7FRR00423L)4> sender:init(pid(6075,50,0),take_this_message).
<0.55.0>
{error,"no answer!"}
(bar@W7FRR00423L)5> sender:init(pid(6075,53,0),take_this_message).
<0.57.0>
{ok,"ok thanks !"}  
(bar@W7FRR00423L)6> sender:init(pid(6075,55,0),"Wassup!").        
<0.59.0>
{error,"no answer!"}
(bar@W7FRR00423L)7>

[编辑]

正如评论中所述,当独立创建2个进程时,通常会通过注册进程(在单个节点上也是如此),例如,您可以像这样修改接收器:

start() ->
    PID = spawn(?MODULE, message_box, []),
    register(?MODULE,PID),
    PID.

然后使用语法{name,node}发送消息以发送消息:sender:init({receiver,bar@W7FRR00423L},take_this_message).

或者您可以从一个节点创建2个进程,如下所示:

(foo@W7FRR00423L)4> Pid = rpc:call(bar@W7FRR00423L,receiver,start,[]).           
<5974.54.0> 
(foo@W7FRR00423L)5> sender:init(Pid,fish).
<0.50.0>
{ok,"So long and thanks for all the fish"}
(foo@W7FRR00423L)6>