Beginner OTP question

Bill Mill bill.mill@REDACTED
Fri Feb 18 14:21:51 CET 2005


On Fri, 18 Feb 2005 00:30:00 -0600, Scott Lystig Fritchie
<fritchie@REDACTED> wrote:
> Here's a unified diff for one way (of several) to fix things up.  I
> removed the bits trying to use global naming service.
> 
> --- myserver.erl        Thu Feb 17 23:29:49 2005
> +++ myserver2.erl       Thu Feb 17 23:28:56 2005
> @@ -2,16 +2,16 @@
> 
>  -behaviour(gen_server).
> 
> --export([start/0, init/1, send/0, handle_call/3]).
> +-export([start/0, init/1, send/1, handle_call/3]).
> 
>  start() ->
> -    gen_server:start({global, myserver}, myserver, [], []).
> +    gen_server:start({local, myserver}, myserver, [], []).

Is the difference between global and local registration that local
registration only occurs on the current node, while global
registration occurs on every node in a distributed system? Is this
documented anywhere else besides the global man page? The reference
manual mentions it but doesn't (AFAICT) describe its use too well.

> 
>  init(_Args) ->
>      {ok, ""}.
> 
> -send() ->
> -    gen_server:call(myserver, send).
> +send(ServerID) ->
> +    gen_server:call(ServerID, send).
> 

gotcha; Ulf got me understanding this a lot better

>  handle_call(send, From, _State) ->
>      io:format("send called from ~p", [From]),
> 
> Then, over on the gbye node, use this function call:
> 
>     myserver:send({myserver, hello@REDACTED}).
> 

beautiful. Like I told Ulf, this is the basic way that I was trying
variations on before I gave up and tried ! .

> On the hello node, you can use:
> 
>     myserver:send(myserver).
>     myserver:send({myserver, node()}).
>     myserver:send({myserver, hello@REDACTED}).
> 
> If you'd started the server on hello using:
> 
>     {ok, MyServerPid} = myserver:start().
> 
> Then this would work, too:
> 
>     myserver:send(MyServerPid).
> 
> Using the list_to_pid() function is generally frowned upon.  Joe
> Armstrong would say that it allows you to violate the principle of a
> process's "unforgeable name", namely its process ID number.  If you're
> not using a local naming scheme (as shown above) or a global naming
> scheme, either of which maps a well-known name to a process ID, the
> only way you're supposed to know a process ID is if someone else tells
> you what it is.  list_to_pid() allows you to circumvent it.
> 
> One handy trick with the shell is using the history mechanism.  Here,
> at command number 12, I started the server but forgot to save the
> pid.  But I can easily get the real, honest-to-goodness pid after the
> fact.
> 
> (a@REDACTED)12> myserver:start().
> {ok,<0.56.0>}
> (a@REDACTED)13> {ok, MyServerPid} = v(12).
> {ok,<0.56.0>}
> (a@REDACTED)14> myserver:send(MyServerPid).
> send called from {<0.50.0>,#Ref<0.0.0.94>}"Thanks for calling"
> 

cool, thanks.

> In practice, you need someone with a well-known name to act as an
> introducer to help break the ice.(*)  Otherwise, you wouldn't be able to
> communicate with anyone: you wouldn't know any pids at all!
> 

I was gonna cross that bridge when I got there : )

> If over on the gbye node you said:
> 
> (gbye@REDACTED)13> register(a_local_name, self()).
> true
> 
> ... then the shell over on the hello node can easily send messages to
> the shell on gbye.  On the hello node, use:
> 
> (hello@REDACTED)17> {a_local_name, gbye@REDACTED} ! {ice_breaker, MyServerPid}.
> {ice_breaker,<0.56.0>}
> 
> That uses the "!" notation to send a simple message over to
> a_local_name over on gbye@REDACTED(**)
> 
> That message is waiting in the shell process's mailbox over on the
> other node.  You can fetch it by:
> 
> (gbye@REDACTED)19> receive {ice_breaker, Pid} -> Pid end.
> <6348.56.0>
> 
> And then you can use it to call your gen_server process without
> relying on the local name registration scheme.
> 
> (gbye@REDACTED)20> myserver:send(Pid).
> "Thanks for calling"
> 

I think I pretty well understood this from the 'getting started'
section of the manual (although more understanding always helps).
Where I was falling down was in how to communicate with the OTP
gen_server.

> You can do this same message passing stuff between Erlang nodes
> running on different UNIX/Windows/Mac/whatever machines.(****)
> 
> -Scott
> 
> (*) The only other way would be some kind of side communication
> channel.  For example, if you could write a pid to a file and then
> have some other process read the file to get that pid.
> 
> (**) "!" is not used to call a function, like you'd tried to do.  "!"
> is the Erlang primitive to send a message to another process.
> 

It would send an atom to the process. I was desperately trying things
to make the gen_server listen to what I was sending it; one of my
thoughts was that maybe it would dispatch a function based the name of
an atom it received.

> The gen_server:call() function ends up using this notation to
> send the message, but it hides some additional details from you.  So
> does the gen_server code receiving side.  When using gen_server, you
> usually don't need to know the details.
> 
> (***) I dunno where this file lives on a Windows platform, sorry.
> 
> (****) It's common to run into a problem with an Erlang security
> mechanism: there's a file called ".erlang.cookie" that's placed in
> your UNIX home directory(***).  If your machines don't have a common
> home directory (e.g. via NFS), then you'll have to copy one machine's
> ".erlang.cookie" file over to the other machine, then restart both
> Erlang nodes.
> 

I've got the cookie set up correctly. I had passed messages before,
but couldn't understand how to make it work with gen_server.

Peace
Bill Mill
bill.mill at gmail.com



More information about the erlang-questions mailing list