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