2009-06-11 8 views
1

Nachdem ich this article gesehen habe, habe ich mit mochiweb getüftelt. Beim Versuch zu replizieren, was in dem Artikel getan wird - im Grunde ein Mochiweb-Server einrichten, mit zwei Erlang-Knoten, und dann eine Funktion in einem Knoten in der anderen (nach dem Festlegen von net_adm: ping() zwischen den beiden Knoten, so dass sie beide wissen andere).Ausnahmefehler: undefined Funktion in Mochiweb/Erlang

Ich konnte alles bis zu diesem Funktionsaufruf Teil folgen. In n1 @ localhost, der der mochiweb Server ist, nenne 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 definiert Funktion:

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 nur die relevanten Teile des Codes eingefügt haben. 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 ist es sagt dass die Login-Funktion, die in n1 @ localhost aufgerufen wird, nicht definiert ist - aber sie ist in n2 @ localhost definiert (und beide Knoten kennen sich gegenseitig - ich habe nodes(). überprüft) !! Bitte sag mir, wo ich falsch liege!

Antwort

1

Sie haben Recht - der Code für Router: Login ist nicht wirklich auf Ihrem Host verfügbar n1 @ localhost - es ist der Code innerhalb dieser Funktion (der gen_server: Anruffunktion), der den Anruf an n2 @ localhost leitet (über das ? SERVER-Makro) und das ist, wo die echte Implementierung ist. Die Top-Level-Funktion ist einfach eine Möglichkeit, diesen Aufruf an den entsprechenden Knoten weiterzuleiten.

Aber Sie müssen zumindest die Umsetzung Login

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

auf n1 @ localhost.

(aktualisiert)

Sie benötigen würde zu definieren, ersetzen oder uns ein? SERVER Makro auch. In dem Beispielcode in dem Artikel ist die

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

aber nutzt das? MODULE Makro, das in Ihrem Fall falsch wäre. Wenn der gen_server-Prozess (Router) gestartet wird, registriert er sich selbst als "MODUL", in diesem Fall wird dies dem "Router" des Atoms zugeordnet, den andere Knoten sehen können (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, den Router unter der Annahme gen_server Prozess ausgeführt wird und hat sich registriert. Der Rückgabewert dieses Aufrufs kommt zu Ihrem Prozess auf n1 @ localhost zurück.

+0

ändern Bedeutet das, ich muss nur die oben genannten zwei Zeilen in der Mochiweb/Erl-Skript (und die Deklaration -export ([Login/2])). Wenn ich das tue, bekomme ich "undefined Makro '' SERVER ''" Fehler. Wenn ich "% -behaviour (gen_server)." Verwende, dann muss ich die Standardfunktionen übersteuern. – thomas55

+0

Oder fehlt mir noch etwas offensichtliches? Muss ich die Datei router.erl im selben Ordner wie das mochiweb-Skript speichern? Currenly, ich mache das nicht ... – thomas55

+0

Ich bearbeite meine ursprüngliche Antwort .... –

0

In den Beispielen in Ihrer Frage sieht es so aus, als ob Sie nur das Modul router auf einen Knoten geladen haben. Knoten laden standardmäßig nicht automatisch Code von einander, nur weil die Funktion auf n2 definiert ist, bedeutet das nicht, dass Sie sie lokal auf n1 aufrufen können (n1 müsste in der Lage sein, es normal zu laden).

Der angegebene Code sieht so aus, als würde er die Ausführung in einem verteilten System korrekt bewältigen (Sie können den Routerserver auf einem Knoten starten und die API-Funktionen auf anderen Knoten aufrufen, um Routeranforderungen an den richtigen Ort zu senden).Sie müssen also nur eine Kopie des router Moduls auf n1 setzen und es sollte einfach funktionieren. Es ist möglich, n1 das Modul router von n2 zu laden, aber es ist ein bisschen mühsam, wenn man n1 nur eine Kopie des Moduls in seinem Code-Pfad gibt.

Interessanterweise ist es im Router-Code nicht notwendig, gen_server:call(global:whereis_name(?MODULE, Message)). zu tun, da die gen_server:call/2-Funktion weiß, wie globale Registrierungen selbst gesucht werden. -define(SERVER, {global, ?MODULE}). würde gut funktionieren, wenn Sie die Funktion start_link zu start_link() -> gen_server:start_link(?SERVER, ?MODULE, [], []).

+0

Alles klar, danke. Wenn Sie meinen "Sie müssen also nur eine Kopie des Router-Moduls auf n1 setzen und es sollte einfach funktionieren." - Meinst du nur die Definitionen kopieren, wie Alan oben geschrieben hat? Das funktioniert gut. – thomas55

+0

Auf n2 hast du router.beam, genau die selbe Strahldatei (und genau dieselbe erlang Quelle) sollte auch auf n1 funktionieren - vorausgesetzt, dass router: start [_link] nur auf n2 aufgerufen wird, während router: login von beiden aufgerufen werden kann Knoten. (Um sicherzustellen, dass der Router-Server auf n2 läuft, können jedoch Anfragen von überall gestellt werden). – archaelus