簡體   English   中英

erlang 將消息從服​​務器傳遞到不同的節點

[英]erlang pass message from server to a different Node

我試圖讓一個簡單的 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 個節點,使用另一個節點的名稱啟動服務器,但是當我嘗試使用服務器傳遞消息時! “一些消息”它崩潰了。 我在這里做錯了什么? 我如何注冊一個進程並調用它以便它在另一台機器上執行?

您收到 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> 

為了使這成為可能,您需要使用Distributed Erlang 為了在節點之間傳遞消息,它們需要集群。 這是通過使用 cookie 來完成的。 為了說明這一點,我將使用來自LYSE的示例(Fred Hèbert,2013 年)。

首先我們啟動兩個節點

erl -sname node1 -setcookie 'asd11'
erl -sname node2 -setcookie 'asd11'

檢查節點是否已連接net_kernel:connect_node('node2@polar')

我們在兩者上注冊了一個控制台進程本身

(node1@polare)1> register(server, self()).
(node2@polare)1> register(client, self()).

我們將讓服務器回答來自客戶端的傳入消息。 在 node1 上我們做

receive {hello, from, OtherShell} -> OtherShell ! <<"hey there!">> end.

現在可以從客戶端發送消息。

{server, node1@polar} ! {hello, from, self()}.

在第一個節點上,您應該看到<<"hey there!">>打印在其控制台中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM