首页 > 解决方案 > erlang将消息从服​​务器传递到不同的节点

问题描述

我正在尝试让一个简单的 erlang 服务器在我尝试注册服务器的地方工作,将消息传递给服务器,该服务器应该在不同的节点上注册并创建 2 个进程,但我收到了这个错误:

{badarg,[{erlang,register,[printer1,<12172.86.0>],[]},
         {testerl,server,1,[{file,"testerl.erl"},{line,13}]}]}

我的代码:

-module(testerl).
-export([start_server/1,
    server/1,
    printer/0
    ]).


server(Node_1) ->
    receive
        finished ->
            exit(normal);
        {Message} ->
            register(printer1, spawn(Node_1, testerl, printer, [])),
            register(printer2, spawn(Node_1, testerl, printer, [])),
            {printer1, Node_1} ! {Message},
            {printer2, Node_1} ! {Message},
            server(Node_1)
    end.

printer() ->
    receive
        finished->
            exit(normal);
        {Message} ->
            io:format("printer received msg ~p~n", [Message]),
            server ! finished   
    end.

start_server(Node_1) ->
    register(server, spawn(testerl, server, [Node_1])).

我可以使用 erl -sname [name] 启动 2 个节点,使用另一个节点的名称启动服务器,但是当我尝试使用服务器传递消息时!“一些消息”它崩溃了。我在这里做错了什么?我如何注册一个进程并调用它以便它在另一台机器上执行?

标签: erlangdistributed-computing

解决方案


您收到 badarg 错误是因为您尝试通过 erlang:register/2 注册非本地 Pid。

文档(http://erlang.org/doc/man/erlang.html)表明:

badarg
    If PidOrPort is not an existing local process or port.

spawn(Node_1,...) 的结果是另一个节点(即 Node_1)上的 Pid。如果你想注册一个非本地的 Pid,你可以使用 global:register_name。

所以:

-module(testerl).
-export([start_server/1,
    server/1,
    printer/0
    ]).

server(Node_1) ->
  receive
    finished ->
      exit(normal);
    {Message} ->
      global:register_name(printer1, spawn(Node_1, testerl, printer, [])),
      global:register_name(printer2, spawn(Node_1, testerl, printer, [])),
      global:send(printer1, {Message}),
      global:send(printer2, {Message}),
      server(Node_1)
    end.

printer() ->
    receive
        finished->
            exit(normal);
        {Message} ->
            io:format("printer received msg ~p~n", [Message]),
            global:send(server, finished)   
    end.
start_server(Node_1) ->
    global:register_name(server, spawn(testerl, server, [Node_1])).

运行这个,我得到:

(node1@f0189805e911)59> testerl:start_server('node2@f0189805e911').
(node1@f0189805e911)60> yes
(node1@f0189805e911)61> global:send(server,{test}).                
(node1@f0189805e911)62> printer received msg test
(node1@f0189805e911)63> printer received msg test

当然,不需要使用注册进程:

-module(testerl).
-export([start_server/1,
    server/3,
    printer/1
    ]).

server(Node_1, P1, P2) ->
  receive
    finished ->
      exit(normal);
    {Message} ->
      P1 !  {Message},
      P2 !  {Message},
      server(Node_1, P1, P2)
    end.

printer(ServerPid) ->
    receive
        finished->
            exit(normal);
        {Message} ->
            io:format("printer received msg ~p~n", [Message]),
            ServerPid ! finished   
     end.
start_server(Node_1) ->
  P1 =  spawn(Node_1, testerl, printer, [self()]),
  P2 =  spawn(Node_1, testerl, printer, [self()]),
  spawn(testerl, server, [Node_1, P1, P2]).

运行这个:

(node1@f0189805e911)14> Pid = testerl:start_server('node2@f0189805e911').
<0.117.0>
(node1@f0189805e911)15> Pid ! {test}.                                         
{test}
printer received msg test
printer received msg test
(node1@f0189805e911)16> 

推荐阅读