質問

この記事を見た後に、私はmochiwebでいじってきました。記事で行われているものに複製しようとしていますが - 基本的に2つのErlangのノードを有する、mochiwebサーバをセットアップした後、net_adm設定した後に(他に一つのノードで定義された関数を呼び出す:彼らはそれぞれを知っているので、2つのノード間)のping(他)。

私は、その関数の呼び出し部分まですべてを追跡することができました。 mochiwebサーバであるN1 @ localhostの、で、私は(記事中で行わ同じように)呼び出します:

router:login(IdInt, self()).

そして、router.erlスクリプトですN2 @ localhostの、で、私は、ログイン機能を定義しています:

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

私は、コードの関連部分のみを貼り付けています。しかし、私は今、ブラウザ上のWebサーバにアクセスするときに - 私は、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}}
基本的には、ログイン機能が定義されていないN1の@ localhostの中で呼び出されていることを述べている - -

は、周りのグーグルでの後、私はエラーが言おうとしているものの基本的な要点を得たが、それが(と両方N2の@ localhostの中で定義されていますノードがお互いを知っている - 私は)チェックするnodes().をしました!私が間違っているつもりですどこを教えてください!

役に立ちましたか?

解決

あなたは正しいです - ルータのためのコード:ログインはあなたのホストのN1 @ localhostのに利用でき、実際にはない - それは、その関数内のコード(gen_server:関数を呼び出す)であることを経由してN2 @ localhostのへのルートの呼び出し(?サーバーマクロ)と実際の実装がどこにあるというのです。トップレベルの機能は、単に、適切なノードへのコールをラップする方法である。

しかし、あなたは、ログインの少なくとも実装が必要なのです。

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

N1の@ localhostの上で利用できるます。

(更新)

あなたにも?サーバーマクロを定義置き換えるか、私たちする必要があると思います。記事のサンプルコードでは、これは、

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

これはあなたのケースで間違っているのでしょうか?MODULEマクロを使用しています。 ?gen_serverプロセス(ルータ)が開始されたときに、基本的には他のノードが見ることができる原子「ルータ」にマッピングし、この場合には、モジュールとして自身を登録(グローバル使用:whereis_name(ルータ))。だから、あなただけ書くことができる必要があります:

login(Id, Pid) when is_pid(Pid) ->
    gen_server:call(global:whereis_name(router), {login, Id, Pid}).
プロセスが実行されていると自分自身を登録しているgen_serverルータを想定し、N2の@ localhostの上handle_call方法:

N1 @ localhostの上でログインを呼び出した効果はルータにgen_serverコールになるだろうので。その呼び出しの戻り値をn1 @ localhostの上のあなたのプロセスに戻ってきます。

他のヒント

あなたが1つのノード上でのみrouterモジュールをロードしたように、

あなたの質問の例ではそれが見えます。ノードは、デフォルトで自動的に機能がN2に定義されているため、これだけ(n1は通常の方法でそれをロードできるようにする必要があります)あなたがN1上でローカルにそれを呼び出すことができるという意味ではありません。 それは、分散システムで実行中で適切に対処するように

与えられたコードは、(1つのノード上のルータ・サーバを起動することができ、他のノード上のAPI関数を呼び出すと、正しい場所にルータ要求を送信します)になります。だから、あなただけN1にrouterモジュールのコピーを配置する必要があり、それだけで動作するはずです。これは、N2からN1負荷にrouterモジュールを持つことが可能だが、それだけでそのコードパスでモジュールのコピーをN1与えるに比べて手間のビットです。

gen_server:call(global:whereis_name(?MODULE, Message)).関数はグローバル登録自体をルックアップする方法を知っているように、

興味深いことに、ルータのコードでは、gen_server:call/2を行うには不要です。あなたが

-define(SERVER, {global, ?MODULE}).するのSTART_LINK機能を変更した場合start_link() -> gen_server:start_link(?SERVER, ?MODULE, [], []).は正常に動作します
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top