Pergunta

Depois de ver este artigo , eu fui mexer com mochiweb. Enquanto tenta replicar o que está feito no artigo - basicamente como configurar um servidor mochiweb, tendo dois nós Erlang, e em seguida, chamar uma função definida em um nó na outra (depois de definir net_adm: mesa de ping () entre os dois nós para que eles conheçam cada outro).

Eu era capaz de acompanhar tudo até essa parte chamada de função. Em n1 @ localhost, que é o servidor mochiweb, eu chamo (assim como fez no artigo):

router:login(IdInt, self()).

E, em seguida, no n2 @ localhost, que é o script router.erl, tenho definido a função de 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};

Eu ter colado apenas as partes relevantes do código. No entanto, quando eu agora acessar o servidor web no navegador - eu recebo este relatório de erro no 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}}

Depois de googling ao redor, eu tenho uma essência básica do que o erro está tentando dizer - basicamente diz que a função de login sendo chamado no n1 @ localhost não está definido - mas ele está definido no n2 @ localhost (e tanto o nós conhecemos - Eu fiz nodes(). para verificar) !! Por favor, diga-me onde estou indo errado!

Foi útil?

Solução

Você tem razão - o código para router: login não está realmente disponível em seu host n1 @ localhost - é o código dentro dessa função (a gen_server: função de chamada) que encaminha a chamada para n2 @ localhost (via isso? macro SERVER) e é aí que a implementação real é. A função de nível superior é simplesmente uma maneira de envolver-se que a chamada para o nó apropriado.

Mas você precisa, pelo menos, a implementação de logon

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

disponível em n1 @ localhost.

(Actualizado)

Você precisa de definir, substituir ou nos uma? SERVIDOR macro também. No código de exemplo no artigo este é

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

mas isso usa o? MÓDULO macro que seria errado no seu caso. ? Basicamente, quando o processo gen_server (router) é iniciado ele se registra como MÓDULO, neste caso, que mapeia para o átomo 'router' que outros nós pode ver (usando mundial: whereis_name (router)). Então você deve ser capaz de escrever apenas:

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

Assim, o efeito de logon convidando n1 @ localhost iria fazer uma chamada gen_server ao roteador: método handle_call no n2 @ localhost, assumindo o processo gen_server roteador está em execução e foi registrada. O valor de retorno da chamada volta para o seu processo on n1 @ localhost.

Outras dicas

Nos exemplos em sua pergunta, parece que você só carregado o módulo router em um nó. Nós não por padrão carregar automaticamente o código de eachother, por isso só porque a função é definida no n2 não significa que você pode chamá-lo localmente no n1 (n1 precisaria ser capaz de carregá-lo na maneira normal).

O código dado parece que lida adequadamente com o funcionamento em um sistema distribuído (você pode iniciar o servidor roteador em um nó e chamando as funções de API em outros nós enviará solicitações roteador para o local correto). Então você só precisa colocar uma cópia do módulo router em n1 e ele deverá funcionar. É possível ter n1 carregar o módulo router de n2, mas é um pouco de um aborrecimento em comparação com apenas dando n1 uma cópia do módulo em seu caminho de código.

Curiosamente, no código roteador é desnecessário fazer gen_server:call(global:whereis_name(?MODULE, Message)). como a função gen_server:call/2 sabe para procurar-se inscrições globais. -define(SERVER, {global, ?MODULE}). iria funcionar bem se você mudou a função start_link para start_link() -> gen_server:start_link(?SERVER, ?MODULE, [], []).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top