简体   繁体   中英

erlang pass message from server to a different Node

I'm trying to get a simple erlang server to work where I'm trying to register the server, pass messages to the server which should register and create 2 processes on a different Node but I'm getting this error:

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

My code:

-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])).

I can start the 2 Nodes with erl -sname [name], start the server with the name of the other Node but when I try to pass a message with server ! "some message" it crashes. What am I doing wrong here? How can i register a process and call it so it executes on the other machine?

You are getting the badarg error because you are attempting to register a non-local Pid via erlang:register/2.

The documentation ( http://erlang.org/doc/man/erlang.html ) indicates:

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

The result of your spawn(Node_1,...) is a Pid that is on another node (ie, Node_1). If you want to register a non-local Pid, you could use global:register_name.

So:

-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])).

Running this, I get:

(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

Of course, one need not use Registered Processes:

-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]).

Running this:

(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> 

To make that possible you need use Distributed Erlang . To pass messages between nodes they need to be clustered. This is done by using a cookie. To illustrate this I will use an example from LYSE (Fred Hèbert, 2013).

First we start two nodes

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

Check that the nodes are connected net_kernel:connect_node('node2@polar') .

We register a the console process itself on both

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

We will let the server answer to an incoming message from client. On node1 we do

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

Now can send a message from the client.

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

On the first node you should see <<"hey there!">> printed in its console.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM