質問
この記事を見た後に、私は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の上のあなたのプロセスに戻ってきます。
他のヒント
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, [], []).
は正常に動作します