我正在尝试在Erlang中编写第一个程序来实现客户端和服务器之间的消息通信。理论上,服务器在没有收到来自客户端的消息时退出,但每次编辑客户端代码并再次运行服务器时,它都会执行旧代码。我必须^ g> q> erl> [重新输入命令]才能看到新代码。
-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]).
服务器无法从客户端收到消息,但在我能以更直接的方式尝试更改代码之前,我无法明智地开始调试。
答案 0 :(得分:2)
当你修改模块时,你需要编译它。
如果使用命令c(模块)或c(模块,[options])在erlang shell中执行此操作,则模块的新编译版本将自动加载到该shell中。它将被您启动的所有新流程使用。
对于那个活着且已经使用它的人来说解释起来更复杂,我认为这不是你所要求的。
如果你运行了几个erlang shell,那么只有编译模块的那个会加载它。这意味着在另一个shell中,如果模块先前已加载,基本上如果您已在这些shell中使用该模块,即使相应的进程已终止,也会忽略新版本。
如果使用命令erlc进行编译,则相同。
在所有这些情况下,您需要在shell中使用命令l(module)显式加载模块。
答案 1 :(得分:0)
您的服务器循环仅包含本地函数调用。仅当存在远程(或外部)函数调用时才会更改运行代码。所以你必须先导出你的循环函数:
-export([loop/3]).
然后您必须将函数loop/3
中的所有receiveLoop/3
次调用更改为
?MODULE:loop(...)
或者,您可以使用receiveLoop/3
执行相同的操作。严肃应用程序的最佳实践是按需求进行热代码交换,因此只有在收到一些特殊消息后才能将loop/3
更改为远程/外部。