看到后 本文, ,我一直在摆弄mochiweb。在尝试复制本文中所做的事情时 - 基本上设置一个 mochiweb 服务器,有两个 erlang 节点,然后调用另一个节点中一个节点中定义的函数(在两个节点之间设置 net_adm:ping() 以便它们知道每个节点之后)其他)。

我能够跟踪一切,直到函数调用部分。在 n1@localhost(即 mochiweb 服务器)中,我调用(正如文章中所做的那样):

router:login(IdInt, self()).

然后,在 n2@localhost(即 router.erl 脚本)中,我定义了登录函数:

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

我只粘贴了代码的相关部分。但是,当我现在在浏览器上访问网络服务器时 - 我在 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(). 去检查) !!请告诉我哪里错了!

有帮助吗?

解决方案

你是对的 - router:login 的代码实际上在您的主机 n1@localhost 上不可用 - 它是该函数(gen_server:call 函数)中的代码,它将调用路由到 n2@localhost (通过那个 ?SERVER 宏)这就是真正的实施所在。顶级函数只是将调用包装到适当节点的一种方法。

但你至少需要实现登录

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

在 n1@localhost 上可用。

(更新)

您还需要定义、替换或使用 ?SERVER 宏。在文章的示例代码中,这是

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

但这使用了 ?MODULE 宏,这在您的情况下是错误的。基本上,当 gen_server 进程(路由器)启动时,它将自身注册为 ?MODULE,在本例中映射到其他节点可以看到的原子“路由器”(使用 global:whereis_name(router) )。所以你应该可以这样写:

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

因此,假设路由器 gen_server 进程正在运行并已注册,则在 n1@localhost 上调用登录的效果将对 n2@localhost 上的 router:handle_call 方法进行 gen_server 调用。该调用的返回值返回到 n1@localhost 上的进程。

其他提示

在你的问题的例子,它看起来像你只加载router模块在一个节点上。节点默认情况下不会自动加载的海誓山盟代码,所以只是因为该函数是在N2定义并不意味着你可以在本地调用它的N1(N1将需要能够加载它以正常的方式)。

在代码中给出看起来像它在分布式系统中运行正常科佩斯(你可以在一个节点上启动路由服务器,并呼吁其他节点的API函数将发送路由器请求传送到正确的地方)。所以,你只需要把N1上的router模块的副本,它应该只是工作。这可能有N1负荷N2的router模块,但它是一个有点麻烦相比,只是给在其代码路径N1上的模块的副本。

有趣的是,在路由器代码,这是不必要的,因为gen_server:call(global:whereis_name(?MODULE, Message)).函数知道如何查找全球注册本身做gen_server:call/2。如果你改变了START_LINK功能-define(SERVER, {global, ?MODULE}). start_link() -> gen_server:start_link(?SERVER, ?MODULE, [], []).会正常工作

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top