Domanda

Dopo aver visto questo articolo , ho armeggiare con mochiweb. Durante il tentativo di replicare ciò che è fatto in questo articolo - in sostanza la creazione di un server di mochiweb, avendo due nodi Erlang, e quindi chiamando una funzione definita in un nodo all'altro (dopo aver impostato net_adm: ping () tra i due nodi in modo da conoscere ogni altro).

Sono stato in grado di seguire tutto ciò fino a quella parte chiamata di funzione. In n1 @ localhost, che è il server mochiweb, mi chiamo (proprio come avviene in questo articolo):

router:login(IdInt, self()).

E poi, in N2 @ localhost, che è lo script router.erl, ho definito la funzione di login:

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

ho incollato solo le parti rilevanti del codice. Tuttavia, quando ora accedo il server web sul browser - ottengo questo rapporto di errore sulla 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}}

Dopo googling intorno, ho ricevuto una sostanza di base di ciò che l'errore sta cercando di dire - in fondo si dice che la funzione di login viene chiamata in n1 @ localhost non è definito - ma è definito in N2 @ localhost (e sia il nodi conoscono - ho nodes(). controllare) !! Ti prego, dimmi dove sto andando male!

È stato utile?

Soluzione

Hai ragione - il codice per router: accesso non è effettivamente disponibile sul proprio host n1 @ localhost - è il codice all'interno di tale funzione (la gen_server: funzione di chiamata), che instrada la chiamata al n2 @ localhost (via così? SERVER macro) ed è lì che la vera implementazione è. La funzione di livello superiore è semplicemente un modo di confezionamento di quella chiamata al nodo appropriato.

Ma si ha bisogno di almeno l'attuazione di login

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

accessibile n1 @ localhost.

(Aggiornato)

Si sarebbe necessario definire, sostituire o noi una? SERVER macro pure. Nel codice di esempio in questo articolo è

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

ma questo utilizza il? Macro MODULO che sarebbe sbagliato nel vostro caso. ? Fondamentalmente, quando si avvia il processo di gen_server (router) che si registra come MODULO, in questo caso, che mappa l'atomo 'router', che altri nodi possono vedere (usando globale: whereis_name (router)). Così si dovrebbe essere in grado di scrivere solo:

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

Così l'effetto di chiamare login su n1 @ localhost sarebbe effettuare una chiamata gen_server al router: metodo di handle_call su n2 @ localhost, supponendo che il router gen_server processo è in esecuzione e si è registrato. Il valore di ritorno di quella chiamata torna al vostro processo su n1 @ localhost.

Altri suggerimenti

Negli esempi nella tua domanda sembra che è stato caricato solo il modulo router su un nodo. I nodi non di default caricano automaticamente il codice l'uno dall'altro, così solo perché la funzione è definita sulla n2 non significa che si può chiamare localmente sul n1 (n1 avrebbero bisogno di essere in grado di caricare in modo normale).

Il codice dato sembra che affronta correttamente con in esecuzione in un sistema distribuito (è possibile avviare il router server su un nodo e chiamando le funzioni API su altri nodi invierà le richieste del router al posto giusto). Quindi non vi resta che mettere una copia del modulo router sulla N1 e dovrebbe funzionare. E 'possibile avere il carico n1 il modulo router da n2, ma è un po' di fastidio rispetto ad appena dare n1 una copia del modulo nel suo percorso di codice.

È interessante notare che, nel codice router è necessario fare gen_server:call(global:whereis_name(?MODULE, Message)). come la funzione gen_server:call/2 sa occhiata si immatricolazioni globali. -define(SERVER, {global, ?MODULE}). avrebbe funzionato bene se è stata modificata la funzione start_link a start_link() -> gen_server:start_link(?SERVER, ?MODULE, [], []).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top