如果我使用register(atom, spawn..)
或Pid = spawn..
注册新生成的流程,会有所不同吗?
举一个例子,我只是用编程Erlang书中的一个旧程序来做到这一点:
让我们首先制作一个简单的服务器循环:
-module(geometry_server).
-export([loop/0]).
loop() ->
receive
{Client, {square, S} = Tuple} ->
io:format("Server: Area of square of Side ~p is ~p and Client was ~p~n", [S, S*S, Client]),
Client ! {self(), Tuple, S*S},
loop()
end.
现在是客户:
-module(geometry_client).
-export([client/2, start_server/0]).
client(Pid_server, Geom_tuple) ->
Pid_server ! {self(), Geom_tuple},
receive
{Pid_server, Geom_tuple, Area} -> io:format("Client: Area of ~p is ~p and server was ~p~n", [Geom_tuple, Area, Pid_server])
after 1000 ->
io:format("~p~n",["received nothing from server"] )
end.
start_server() -> spawn(geometry_server, loop, []).
编译后,我做
register(q, Q = geometry_client:start_server()).
然后我打电话给他们,得到如下结果:
5> geometry_client:client(Q, {square,2}).
Server: Area of square of Side 2 is 4 and Client was <0.60.0>
Client: Area of {square,2} is 4 and server was <0.77.0>
ok
6> geometry_client:client(q, {square,2}).
Server: Area of square of Side 2 is 4 and Client was <0.60.0>
"received nothing from server"
ok
为什么客户端在使用注册的atom时没有收到服务器上的任何内容?服务器显然收到了来自客户端的消息。
我可以确认服务器发送了一条消息,因为上面的话后我做了
7> geometry_client:client(whereis(q), {square,2}).
Client: Area of {square,2} is 4 and server was <0.77.0>
Server: Area of square of Side 2 is 4 and Client was <0.60.0>
ok
12>
所以我得出结论,邮箱已经有来自上一个命令的来自服务器的消息,这就是在收到并打印服务器消息之前打印客户端输出的原因......
我错过了什么?当我使用已注册的原子时,为什么接收消息时出现问题?
答案 0 :(得分:3)
receive
函数中的client/2
等待与{Pid_server, Geom_tuple, Area}
匹配的邮件。当您传递q
作为参数时,Pid_server
为q
,但服务器将返回的消息发送到客户端是一个元组,第一个元素始终是服务器的实际PID,而不是其名称,这意味着您的receive
最终会出现在after
区块中。
有很多方法可以解决这个问题。您可以修改client/2
以使用whereis/1
获取已注册流程的PID,并在receive
中使用{如果Pid_server
是原子。
最好的方法是在这里使用引用(参见make_ref/0
)。在向服务器发送消息时创建引用,服务器将其发送回响应中。这样,您就可以保证您已收到刚刚发送的请求的回复,因为make_ref/0
返回的每个引用都保证是唯一的。
在client/2
中,执行:
client(Pid_server, Geom_tuple) ->
Ref = make_ref(),
Pid_server ! {Ref, self(), Geom_tuple},
receive
{Ref, Geom_tuple, Area} -> io:format("Client: Area of ~p is ~p and server was ~p~n", [Geom_tuple, Area, Pid_server])
after 1000 ->
io:format("~p~n",["received nothing from server"] )
end.
在服务器中:
loop() ->
receive
{Ref, Client, {square, S} = Tuple} ->
io:format("Server: Area of square of Side ~p is ~p and Client was ~p~n", [S, S*S, Client]),
Client ! {Ref, Tuple, S*S},
loop()
end.