1

我正在尝试在 Erlang 中编写第一个影响客户端和服务器之间的消息通信的程序。理论上,服务器在没有收到来自客户端的消息时退出,但每次我编辑客户端代码并再次运行服务器时,它都会执行旧代码。我必须 ^G>q>erl>[re-enter command] 才能看到新代码。

-module(srvEsOne).

%%
%% export functions
%%

-export([start/0]).

%%function definition

start()->
    io:format("Server: Starting at pid: ~p \n",[self()]),
    case lists:member(serverEsOne, registered()) of
        true ->
            unregister(serverEsOne);                            %if the token  is present, remove it
        false ->
            ok
    end,
    register(serverEsOne,self()),
    Pid = spawn(esOne, start,[self()]),
    loop(false, false,Pid).

%
loop(Prec, Nrec,Pd)->
    io:format("Server: I am waiting to hear from: ~p \n",[Pd]),
    case Prec of
        true ->
            case Nrec of
                true ->     
                    io:format("Server: I reply to ~p \n",[Pd]),
                    Pd ! {reply, self()},
                    io:format("Server: I quit \n",[]),
                    ok;
                false ->
                    receiveLoop(Prec,Nrec,Pd)
            end;
        false ->
            receiveLoop(Prec,Nrec,Pd)
    end.

receiveLoop(Prec,Nrec,Pid) ->
    receive
        {onPid, Pid}->
            io:format("Server: I received a message to my pid from ~p \n",[Pid]),
            loop(true, Nrec,Pid);
        {onName,Pid}->
            io:format("Server: I received a message to name from ~p \n",[Pid]),
            loop(Prec,true,Pid)
    after
        5000->
            io:format("Server: I received no messages, i quit\n",[]),
            ok
    end.

客户端代码读取

-module(esOne).

-export([start/1, func/1]).

start(Par) ->
    io:format("Client: I am ~p, i was spawned by the server: ~p \n",[self(),Par]),

    spawn(esOne, func, [self()]),
    io:format("Client: Now I will try to send a message to: ~p \n",[Par]),
    Par ! {self(), hotbelgo},
    serverEsOne ! {self(), hotbelgo},

    ok.



func(Parent)->
    io:format("Child: I am ~p, i was spawned from ~p \n",[self(),Parent]).

服务器无法从客户端接收消息,但在我可以尝试以更直接的方式更改代码之前,我无法明智地开始调试。

4

2 回答 2

2

当您对模块进行修改时,您需要编译它。

如果您在 erlang shell 中使用命令 c(module) 或 c(module,[options]) 执行此操作,则模块的新编译版本会自动加载到该 shell 中。您启动的所有新进程都将使用它。

对于还活着并且已经使用它的人来说,解释起来更复杂,我认为这不是你想要的。

如果你有几个 erlang shell 正在运行,那么只有你编译模块的那个会加载它。这意味着在另一个 shell 中,如果以前加载了该模块,基本上如果您已经在那些 shell 中使用了该模块,并且即使相应的进程被终止,新版本也会被忽略。

如果你使用命令 erlc 编译也是一样。

在所有这些情况下,您需要在 shell 中使用命令 l(module) 显式加载模块。

于 2013-10-26T10:02:13.787 回答
0

您的服务器循环仅包含本地函数调用。仅当存在远程(或外部)函数调用时,才会更改运行代码。所以你必须先导出你的循环函数:

-export([loop/3]).

然后你必须将loop/3函数中的所有调用更改receiveLoop/3

?MODULE:loop(...)

或者,您可以改为使用相同的方法receiveLoop/3。严肃应用程序的最佳实践是按需进行热代码交换,因此您loop/3只有在收到一些特殊消息后才更改为远程/外部。

于 2013-10-26T11:30:40.257 回答