我对Erlang很新,但是我一直在尝试创建一个简单的客户端服务器实现。服务器会假设创建工作进程以在“数据库”中执行“繁重的工作”,然后将计算的值返回给客户端。
我目前的步骤是:
以下是一些示例代码。
-module(server).
-compile(export_all).
server() ->
receive
{From, {client, Name}} ->
io:format("Server has received request for ~p from ~p~n", [Name, From]),
Worker = spawn(server, getNameFromDataBase(self()),[]),
Worker ! Name,
From ! LastName,%%data returned from worker
server();
{database, LastName} ->
Data = LastName,
server()
end.
getNameFromDataBase(Server_Address) ->
receive
{name, Name} ->
timer:sleep(5000), %doing difficult work!
Server_Address ! {database, "Johnson"}
end.
client(Server_Address) ->
Server_Address ! {self(), {client, "Jim"}},
receive
{server, LastName} ->
io:format("Server got person's last name~p~n", LastName)
end.
如何制作以便从工作人员那里收到的数据能够被发送到客户端?
答案 0 :(得分:3)
我可以看到服务器进程有两个主要问题:
向工作人员发送消息
以下L8 - L10代码行不正确。
%% ...
Worker = spawn(server, getNameFromDataBase(self()), []),
Worker ! Name,
From ! LastName,
%% ...
要将函数生成为进程,必须在spawn/3
的第三个参数中为函数提供任何参数作为列表成员,而不是直接调用函数。
Worker = spawn(server, getNameFromDataBase, [self()]),
Name
期待Worker
,因此只会getNameFromDataBase
向{name, Name}
发送,但不会被注意到。这应该改为
Worker ! {name, Name}
将结果(LastName)发送到客户端
由于您尚未收到From ! LastName
,因此在L10上发送LastName
没有意义。当服务器从工作程序收到{database, LastName}
时,应将其移动到第二个匹配表达式。
此外,client
预计{server, LastName}
,而非LastName
。所以应该是From ! {server, LastName}
。
但是,有一个问题。您无法访问该范围内的From
,因为它从未被定义过。
%% ...
{database, LastName} ->
From ! {server, LastName}, % `From` is not defined
server()
%% ...
在不必更改消息元组的情况下,您可能想要做的是定义另一个server/1
函数,如下所示:
server(ClientPID) ->
receive
{_, LastName} ->
ClientPID ! {server, LastName},
server()
end.
并从server/0
:
server() ->
receive
{From, {client, Name}} ->
io:format("Server has received request for ~p from ~p~n", [Name, From]),
Worker = spawn(?MODULE, getNameFromDataBase, [self()]),
Worker ! {name, Name},
server(From) % call `server/1` with the client's PID
end.
最后,要包装所有内容,如果还没有,请创建一个启动函数来生成server
和client
进程。这是完成的代码:
server() ->
receive
{From, {client, Name}} ->
io:format("Server has received request for ~p from ~p~n", [Name, From]),
Worker = spawn(?MODULE, getNameFromDataBase, [self()]),
Worker ! {name, Name},
server(From)
end.
server(ClientPID) ->
receive
{_, LastName} ->
ClientPID ! {server, LastName},
server()
end.
getNameFromDataBase(ServerAddr) ->
receive
{name, Name} ->
io:format("worker received ~p~n",[Name]),
timer:sleep(5000),
ServerAddr ! {database, "Johnson"}
end.
client(ServerPID) ->
ServerPID ! {self(),{client, "Jim"}},
receive
{server, LastName} ->
io:format("Client got person's last name ~p from Server ~n", [LastName])
end.
run() ->
ServerPID = spawn(?MODULE, server, []),
spawn(?MODULE, client, [ServerPID]).
最后提示:不要使用export_all
编译选项。只导出必要的功能以实现良好的封装。
答案 1 :(得分:1)
您将收到来自收件人{database, LastName} ->
分支中的工作人员的消息。只需在消息本身中包含处理它所需的信息:
server() ->
receive
{From, {client, Name}} ->
io:format("Server has received request for ~p from ~p~n", [Name, From]),
Worker = spawn(server, getNameFromDataBase, [self()]),
Worker ! {name, From, Name},
server();
{database, From, LastName} ->
From ! LastName,
server()
end.
getNameFromDataBase(Server_Address) ->
receive
{name, From, Name} ->
timer:sleep(5000), %doing difficult work!
Server_Address ! {database, From, "Johnson"}
end.
请注意,参数需要在列表中传递(spawn
的第三个参数)。此外,如果您创建工作程序只是为了立即发送单个消息,您也可以将其内容作为参数传递;我没有在这里做这个改变,以便更容易看到主要的变化。
或者,您可以将From
对应的Worker
存储在服务器状态(server()
的参数)。