Frage

Nach der Besichtigung diesem Artikel , habe ich mit mochiweb bastelt. Bei dem Versuch, zu wiederholen, was in dem Artikel fertig ist - Einstellung im Grunde ein mochiweb Servers, zwei erlang Knoten, und dann eine Funktion definiert in einem Knoten in der anderen der Telefonnummer (nach dem Abbinden net_adm: ping () zwischen den beiden Knoten, so dass sie jeder kennen andere).

Ich konnte alles bis zu diesem Funktionsaufruf Teil folgen. In n1 @ localhost, der den mochiweb Server ist, rufe ich (so wie in dem Artikel gemacht):

router:login(IdInt, self()).

Und dann, in n2 @ localhost, der das router.erl Skript ist, habe ich die Login-Funktion definiert:

login(Id, Pid) when is_pid(Pid) ->
    gen_server:call(?SERVER, {login, Id, Pid}).

handle_call({login, Id, Pid}, _From, State) when is_pid(Pid) ->
          ets:insert(State#state.pid2id, {Pid, Id}),
          ets:insert(State#state.id2pid, {Id, Pid}),
          link(Pid), % tell us if they exit, so we can log them out
          io:format("~w logged in as ~w\n",[Pid, Id]),
          {reply, ok, State};

Ich habe nur die relevanten Teile des Codes eingefügt. Allerdings, wenn ich jetzt den Webserver auf dem Browser zugreifen - Ich erhalte diese Fehlermeldung auf n1 @ localhost:

=CRASH REPORT==== 11-Jun-2009::12:39:49 ===
  crasher:
    initial call: mochiweb_socket_server:acceptor_loop/1
    pid: <0.62.0>
    registered_name: []
    exception error: undefined function router:login/2
      in function  mochiconntest_web:loop/2
      in call from mochiweb_http:headers/5
    ancestors: [mochiconntest_web,mochiconntest_sup,<0.59.0>]
    messages: []
    links: [<0.61.0>,#Port<0.897>]
    dictionary: [{mochiweb_request_path,"/test/123"}]
    trap_exit: false
    status: running
    heap_size: 1597
    stack_size: 24
    reductions: 1551
  neighbours:

=ERROR REPORT==== 11-Jun-2009::12:39:49 ===
{mochiweb_socket_server,235,{child_error,undef}}

Nach googeln um, bekam ich einen grundlegenden Kern von dem, was der Fehler ist versucht zu sagen - im Grunde sagt, dass die Login-Funktion in n1 @ localhost aufgerufen wurde nicht definiert ist - aber es ist in n2 @ localhost definiert (und sowohl die Knoten kennen einander - ich habe nodes(). zu überprüfen) !! Bitte sagen Sie mir, wo ich falsch bin dabei!

War es hilfreich?

Lösung

Sie haben Recht - der Code für den Router: Anmeldung ist auf dem Host-n1 @ localhost nicht tatsächlich zur Verfügung - es ist der Code innerhalb dieser Funktion (die gen_server: call-Funktion), die den Anruf zu n2 @ localhost (über das? SERVER Makro) und das ist, wo die reale Umsetzung ist. Die Top-Level-Funktion ist einfach eine Möglichkeit der Verpackung auf diesen Ruf zu dem entsprechenden Knoten auf.

Aber Sie müssen zumindest die Umsetzung von login

login(Id, Pid) when is_pid(Pid) ->
    gen_server:call(?SERVER, {login, Id, Pid}).

auf n1 @ localhost.

(Aktualisiert)

Sie müssen definieren, ersetzen oder uns ein? SERVER Makro auch. In dem Beispielcode in dem Artikel ist die

-define(SERVER, global:whereis_name(?MODULE)).

, aber das nutzt das? MODULE Makro, das in Ihrem Fall falsch wäre. ? Im Grunde genommen, wenn der gen_server Prozess (Router) gestartet wird, registriert er sich als MODUL, in diesem Fall, die dem Atom ‚Router‘ abbildet, die anderen Knoten sehen können (unter Verwendung von global: whereis_name (Router)). So sollten Sie in der Lage sein, nur schreiben:

login(Id, Pid) when is_pid(Pid) ->
    gen_server:call(global:whereis_name(router), {login, Id, Pid}).

So die Wirkung der Anmeldung auf n1 @ localhost aufrufen würde einen gen_server Anruf an den Router machen: handle_call Methode auf n2 @ localhost, vorausgesetzt, der Router gen_server Prozess läuft und hat sich registriert. Der Rückgabewert dieses Anrufs an Ihren Prozess kommt zurück auf n1 @ localhost.

Andere Tipps

In den Beispielen in Ihrer Frage sieht es aus wie Sie nur das router Modul auf einem Knoten geladen. Knoten standardmäßig nicht automatisch Code aus einander laden, so nur, weil die Funktion auf n2 definiert ist, bedeutet nicht, Sie es lokal auf n1 aufrufen (n1 in der Lage sein müssten es in gewohnter Weise zu laden).

Der Code sieht gegeben, wie es richtig mit dem Betrieb in einem verteilten System meistert (können Sie den Router-Server auf einem Knoten starten und auf anderen Knoten die API-Funktionen aufrufen werden Router-Anfragen an die richtige Stelle senden). Sie müssen also nur eine Kopie des router Modul auf n1 setzen und es sollte einfach funktionieren. Es ist möglich, n1 Last der router Modul von n2 zu haben, aber es ist ein wenig Aufwand im Vergleich zu nur geben Sie eine Kopie des Moduls in seinem Codepfad n1.

Interessanterweise wird in dem Router-Code ist es nicht erforderlich, gen_server:call(global:whereis_name(?MODULE, Message)). wie die gen_server:call/2 Funktion weiß, wie man Nachschlag globale Registrierungen selbst zu tun. -define(SERVER, {global, ?MODULE}). würde gut funktionieren, wenn Sie die START_LINK Funktion start_link() -> gen_server:start_link(?SERVER, ?MODULE, [], []). geändert

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top