Question

Après avoir vu Cet article, j'ai bricolé mochiweb.Tout en essayant de reproduire ce qui est fait dans l'article - essentiellement en configurant un serveur mochiweb, en ayant deux nœuds erlang, puis en appelant une fonction définie dans un nœud dans l'autre (après avoir défini net_adm:ping() entre les deux nœuds pour qu'ils se connaissent chacun autre).

J'ai pu tout suivre jusqu'à cette partie d'appel de fonction.Dans n1@localhost, qui est le serveur mochiweb, j'appelle (comme dans l'article) :

router:login(IdInt, self()).

Et puis, dans n2@localhost, qui est le script router.erl, j'ai défini la fonction de connexion :

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};

J'ai collé uniquement les parties pertinentes du code.Cependant, lorsque j'accède maintenant au serveur Web sur le navigateur, je reçois ce rapport d'erreur sur 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}}

Après avoir cherché sur Google, j'ai compris l'essentiel de ce que l'erreur essaie de dire - en gros, elle dit que la fonction de connexion appelée dans n1@localhost n'est pas définie - mais elle est définie dans n2@localhost (et les deux nœuds se connaissent chacun autre - je l'ai fait nodes(). vérifier) ​​!!S'il vous plaît, dites-moi où je me trompe !

Était-ce utile?

La solution

Vous avez raison - le code pour router:login n'est pas réellement disponible sur votre hôte n1@localhost - c'est le code de cette fonction (la fonction gen_server:call) qui achemine l'appel vers n2@localhost (via cette macro ?SERVER) et c'est là que se trouve la véritable mise en œuvre.La fonction de niveau supérieur est simplement un moyen de conclure cet appel au nœud approprié.

Mais vous avez besoin au moins de la mise en œuvre de la connexion

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

disponible sur n1@localhost.

(Mis à jour)

Vous devrez également définir, remplacer ou utiliser une macro ?SERVER.Dans l'exemple de code de l'article, c'est

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

mais cela utilise la macro ?MODULE qui serait fausse dans votre cas.Fondamentalement, lorsque le processus gen_server (routeur) est démarré, il s'enregistre en tant que ?MODULE, dans ce cas, il correspond à l'atome « ​​routeur » que les autres nœuds peuvent voir (en utilisant global:whereis_name(router) ).Vous devriez donc pouvoir simplement écrire :

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

Ainsi, l'appel de login sur n1@localhost aurait pour effet d'appeler gen_server à la méthode router:handle_call sur n2@localhost, en supposant que le processus gen_server du routeur est en cours d'exécution et s'est enregistré.La valeur de retour de cet appel revient à votre processus sur n1@localhost.

Autres conseils

Dans les exemples de votre question, il semble que vous ayez uniquement chargé le router module sur un nœud.Par défaut, les nœuds ne chargent pas automatiquement le code les uns des autres, donc ce n'est pas parce que la fonction est définie sur n2 que vous pouvez l'appeler localement sur n1 (n1 devrait pouvoir la charger de la manière normale).

Le code donné semble fonctionner correctement dans un système distribué (vous pouvez démarrer le serveur de routeur sur un nœud et appeler les fonctions API sur d'autres nœuds enverra les requêtes du routeur au bon endroit).Il vous suffit donc de mettre une copie du router module sur n1 et cela devrait fonctionner.Il est possible que n1 charge le router module de n2, mais c'est un peu compliqué par rapport à simplement donner à n1 une copie du module dans son chemin de code.

Fait intéressant, dans le code du routeur, il n'est pas nécessaire de faire gen_server:call(global:whereis_name(?MODULE, Message)). comme le gen_server:call/2 La fonction sait comment rechercher elle-même les enregistrements globaux. -define(SERVER, {global, ?MODULE}). fonctionnerait bien si vous changiez la fonction start_link en start_link() -> gen_server:start_link(?SERVER, ?MODULE, [], []).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top