Pregunta

Después de ver este artículo , he estado jugando con mochiweb. Al tratar de replicar lo que se hace en el artículo - básicamente la creación de un servidor mochiweb, que tiene dos nodos de Erlang, y luego llamar a una función definida en un nodo en el otro (después de ajustar net_adm: ping () entre los dos nodos de lo que se conocen otra).

pude seguir todo hasta que una parte llamada a la función. En n1 @ localhost, que es el servidor mochiweb, llamo (al igual que hace en el artículo):

router:login(IdInt, self()).

Y entonces, en n2 @ localhost, que es el guión router.erl, he definido la función de entrada:

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

He pegado sólo las partes pertinentes del Código. Sin embargo, cuando ahora puedo acceder al servidor web en el navegador - consigo este informe de errores en 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}}

Tras Google alrededor, tiene una esencia básica de lo que el error está tratando de decir - que básicamente dice que la función de inicio de sesión que se llama en n1 @ localhost no está definido - pero se define en n2 @ localhost (y tanto el los nodos se conocen entre sí - yo nodes(). para comprobar) !! Por favor, dime dónde voy mal!

¿Fue útil?

Solución

Tiene usted razón - el código para el router: inicio de sesión no está realmente disponible en el host n1 @ localhost - es el código dentro de esa función (el gen_server: llamada de función), que dirige la llamada a n2 @ localhost (a través de eso? SERVIDOR macro) y ahí es donde la puesta en práctica real es. La función de nivel superior es simplemente una manera de concluir que la llamada al nodo apropiado.

Pero sí es necesario, al menos, la aplicación de inicio de sesión

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

disponible en n1 @ localhost.

(Actualizado)

Se necesitaría para definir, reemplazar o nos una? SERVIDOR macro también. En el código de ejemplo en el artículo de esto es

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

pero esto utiliza la macro módulo? Lo que sería mal en su caso. ? Básicamente, cuando se inicia el proceso de gen_server (enrutador) se registra a sí mismo como un módulo, en este caso, que se asigna al átomo 'enrutador' que otros nodos pueden ver (usando mundial: whereis_name (router)). Por lo que debe ser capaz de simplemente escribir:

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

Así que el efecto de llamar a login en n1 @ localhost haría una llamada gen_server al router: Método handle_call en n2 @ localhost, asumiendo el router gen_server proceso está en marcha y se ha registrado. El valor de retorno de llamada que viene de nuevo a su proceso de n1 @ localhost.

Otros consejos

En los ejemplos de su pregunta que parece que sólo se ha cargado el módulo de router en un nodo. Los nodos no por defecto se cargan automáticamente el código de uno al otro, por lo que sólo porque la función se define en n2 no significa que se le puede llamar de forma local en N1 (N1 tendría que ser capaz de cargarlo en la forma normal).

El código da parece que hace frente adecuadamente con el funcionamiento de un sistema distribuido (se puede iniciar el servidor router en un nodo y llamar a las funciones de la API en otros nodos va a enviar peticiones del enrutador al lugar correcto). Por lo que sólo tiene que poner una copia del módulo router de n1 y que sólo se debe trabajar. Es posible tener la carga del módulo n1 n2 de router, pero es un poco complicado en comparación con sólo dar n1 una copia del módulo en su ruta de código.

Es interesante que en el código enrutador que es innecesario hacerlo gen_server:call(global:whereis_name(?MODULE, Message)). como la función gen_server:call/2 sabe cómo las operaciones de búsqueda en sí registros globales. -define(SERVER, {global, ?MODULE}). funcionaría bien si ha cambiado la función START_LINK a start_link() -> gen_server:start_link(?SERVER, ?MODULE, [], []).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top