我正在学习erlang,并且正在尝试编写一个简单的客户端 - 服务器程序。
服务器代码如下:
<default>
<receive channel="channel-1" >
<command name="AAR">
</command>
<action>
<store name="HbH" entity="HbH-id"></store>
<store name="E2E" entity="EtE-id"></store>
<store name="sid" entity="Session-Id"></store>
</action>
</receive>
<send channel="channel-1" >
<action>
<restore name="HbH" entity="HbH-id"></restore>
<restore name="E2E" entity="EtE-id"></restore>
<restore name="sid" entity="Session-Id"></restore>
</action>
<command name="AAA">
<avp name="Session-Id" value="$(sid)" type="string"></avp>
<avp name="Result-Code" value="2001" type="number"></avp>
<avp name="Reply-Message" value="Success" type="string"></avp>
</command>
</send>
</default>
<default>
<receive channel="channel-1" >
<command name="PUR">
</command>
<action>
<store name="HbH" entity="HbH-id"></store>
<store name="E2E" entity="EtE-id"></store>
<store name="sid" entity="Session-Id"></store>
</action>
</receive>
<send channel="channel-1" >
<action>
<restore name="HbH" entity="HbH-id"></restore>
<restore name="E2E" entity="EtE-id"></restore>
<restore name="sid" entity="Session-Id"></restore>
</action>
<command name="PUA">
<avp name="Session-Id" value="$(sid)" type="string"></avp>
<avp name="Result-Code" value="2001" type="number"></avp>
<avp name="Reply-Message" value="Success" type="string"></avp>
</command>
</send>
</default>
从另一个erlang脚本
生成服务器如下-module(frequency_server).
-author("Saurav Prakash").
%% API
-export([init/0]).
init() ->
Frequencies = [1,2,3,4],
listen(Frequencies),
io:format("Server leaving init...~n").
listen(Frequencies) ->
io:format("Server inside init...~n"),
receive
{allocate, Pid} ->
io:format("Request for allocation from ~w~n", [Pid]),
if
length(Frequencies) > 0 ->
Frequency_Selected = random:uniform(length(Frequencies)),
io:format("Freq selected is ~w~n", Frequency_Selected),
Pid ! {ok, Frequency_Selected},
listen(lists:delete(Frequency_Selected, Frequencies));
true ->
io:format("Not available freq...~n"),
Pid ! {error, "Not Available"}
end;
{deallocate, Frequency, Pid} ->
io:format("deallocation request...~n"),
listen([Frequency | Frequencies])
end,
io:format("Server dying...~n").
但是我发现只要服务器在listen()内部,它就会执行 register(server, spawn(frequency_server, init, [])),
io:format("server registered with ~w~n", [whereis(server)]).
并被杀死。
可能是什么问题?
答案 0 :(得分:1)
由于第20行上的io:format/2
调用不正确,进程被终止。io:format/2
的参数应该在列表中,所以:
io:format("Freq selected is ~w~n", Frequency_Selected),
应改为:
io:format("Freq selected is ~w~n", [Frequency_Selected]),
但是你也有其他问题,比如代码分配频率的方式。它通过根据可用频率列表的长度选择一个随机数,然后从列表中删除该数字来实现。仅当频率列表是1-N
范围N
,其中[1]
是列表的长度或特殊情况[4]
时才有效。但是这段代码允许列表成为random:uniform(length([4]))
- 当它具有该值时,由于调用Frequencies
,这种方法每次都会选择频率1,即使另一个进程已经分配了频率1,频率4仍然可用。代码应该在考虑分配之前检查所选数字是否在列表中。另一个问题是,取消分配频率不会检查当前是否分配频率,这允许呼叫者重复解除分配相同的频率,从而不止一次将该频率添加回2%
列表。 / p>
答案 1 :(得分:1)
我在一个干净的Erlang shell中检查了你的代码并且它没有被杀死并等待传入的消息。也许还有一些其他隐藏的活动或环境条件是造成问题的原因。
例如,如果您将server
名称注册到另一个进程,则再次执行此操作时会遇到以下异常:
1> register(server, spawn(fun() -> receive _ -> ok end end)).
true
2> register(server, spawn(frequency_server, init, [])),
2> io:format("server registered with ~w~n", [whereis(server)]).
Server inside init...
** exception error: bad argument
in function register/2
called as register(server,<0.36.0>)
例如,某些其他进程可能会向您已注册的server
进程发送一个应该检查的终止信号。
答案 2 :(得分:1)
你的过程并没有消亡,它正在等待你告诉它的消息:
Eshell V7.2 (abort with ^G)
1> c(frequency_server).
frequency_server.erl:26: Warning: variable 'Pid' is unused
{ok,frequency_server}
2> {Pid, Ref} = spawn_monitor(frequency_server, init, []).
Server inside init...
{<0.40.0>,#Ref<0.0.2.85>}
3> Pid ! {deallocate, 5, "This part of the message is meaningless data."}.
deallocation request...
{deallocate,5,
"This part of the message is meaningless data."}
Server inside init...
4>
请参阅?在那里,只是等待消息,以便它可以执行其令人难以置信的奇怪逻辑。
如果您有时间,可能需要阅读以下不同版本:
-module(wonky_serv).
%% API
-export([init/0]).
init() ->
Frequencies = [1,2,3,4],
ok = io:format("~tp ~tp: Starting with Frequencies: ~tp~n",
[self(), ?MODULE, Frequencies]),
listen(Frequencies).
listen(Frequencies) ->
ok = io:format("~tp ~tp: inside listen(~tp)~n",
[self(), ?MODULE, Frequencies]),
receive
{allocate, Pid} ->
{ok, NewFreqs} = allocate(Frequencies, Pid),
listen(NewFreqs);
{deallocate, Frequency, Pid} ->
{ok, NewFreqs} = deallocate(Frequencies, Frequency, Pid),
listen(NewFreqs);
{terminate, Pid} ->
ok = io:format("~tp ~tp: ~tp told me to terminate, so, bye!~n",
[self(), ?MODULE, Pid]);
Unexpected ->
ok = io:format("~tp ~tp: Unexpected message: ~tp~n",
[self(), ?MODULE, Unexpected]),
listen(Frequencies)
end.
allocate([], Pid) ->
ok = io:format("~tp ~tp: ~tp is requesting allocation, but no freqs available.~n",
[self(), ?MODULE, Pid]),
{ok, []};
allocate([Alloc | Rest], Pid) ->
ok = io:format("~tp ~tp: Allocating Freq ~tp to ~tp~n",
[self(), ?MODULE, Alloc, Pid]),
{ok, Rest}.
deallocate(Freqs, Dealloc, Pid) ->
NewFreqs = [Dealloc | Freqs],
ok = io:format("~tp ~tp: Deallocating ~tp from ~tp~n"
" Available freqs: ~tp~n",
[self(), ?MODULE, Dealloc, Pid, NewFreqs]),
{ok, NewFreqs}.
以下是该版本的用法:
1> {Pid, Ref} = spawn_monitor(wonky_serv, init, []).
<0.35.0> wonky_serv: Starting with Frequencies: [1,2,3,4]
{<0.35.0>,#Ref<0.0.1.44>}
<0.35.0> wonky_serv: inside listen([1,2,3,4])
2> Pid ! {deallocate, 5, self()}.
<0.35.0> wonky_serv: Deallocating 5 from <0.33.0>
Available freqs: [5,1,2,3,4]
{deallocate,5,<0.33.0>}
<0.35.0> wonky_serv: inside listen([5,1,2,3,4])
3> Pid ! {allocate, self()}.
<0.35.0> wonky_serv: Allocating Freq 5 to <0.33.0>
{allocate,0.33.0>}
<0.35.0> wonky_serv: inside listen([1,2,3,4])
4> Pid ! {terminate, self()}.
<0.35.0> wonky_serv: <0.33.0> told me to terminate, so, bye!
{terminate,<0.33.0>}
5> flush().
Shell got {'DOWN',#Ref<0.0.1.44>,process,<0.35.0>,normal}
ok
6>