这是一个简单的 UDP 服务器:
-module(kvstore_udpserver).
-author("mylesmcdonnell").
%% API
-export([start/0]).
start() ->
spawn(fun() -> server(2346) end).
server(Port) ->
{ok, Socket} = gen_udp:open(Port, [binary]),
loop(Socket).
loop(Socket) ->
receive
{udp, Socket, Host, Port, Bin} ->
case binary_to_term(Bin) of
{store, Value} ->
io:format("kvstore_udpserver:{store, Value}~n"),
gen_udp:send(Socket,Host,Port,term_to_binary(kvstore:store(Value)));
{retrieve, Key} ->
io:format("kvstore_udpserver:{retrieve, Value}~n"),
gen_udp:send(Socket,Host,Port,term_to_binary(kvstore:retrieve(Key)))
end,
loop(Socket)
end.
Run Code Online (Sandbox Code Playgroud)
我怎样才能重组这个,以便
a)它,或者至少是它的相关部分,是一个 gen_server,这样我就可以添加到监督树中
b) 通过在单独的进程中处理每条消息来增加并发性。
我已经为我的 TCP 服务器重新实现了 Learn You Some Erlang 中的 sockserv 示例,但我正在努力确定 UDP 的类似模型。
为一个):
您需要取消gen_server行为并实现所有回调函数(这是显而易见的,但值得显式调用)。如果已经rebar安装,可以使用命令rebar create template=simplesrv srvid=your_server_name添加样板函数。
您可能希望将服务器启动业务逻辑(调用gen_udp:open/2)移至服务器的init/1功能。(行为需要 init gen_server。您也可以loop/1在那里启动您的函数。
您可能想要确保 udp 服务器已被模块的terminate/2功能关闭。
将用于处理从解析消息到函数的请求的业务逻辑移至模块loop/1中handle_call/3或handle_cast/2模块中(见下文)。
对于b):您有几个选项,但基本上,每当您收到消息时,您都可以使用gen_server:cast/2(如果您不关心响应)或gen_server:call/2,3如果您这样做。转换或调用将由模块中的 handle_cast/2或函数处理。handle_call/3
强制转换本质上是非阻塞的,这个问题的答案有一个很好的设计模式,可以在gen_servers. 你可以从中抄袭。