这是一个简单的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.
我如何重组这个
a)它,或者至少它的相关部分是gen_server,以便我可以添加到监督树
b)通过在单独的进程中处理每条消息来增加并发性。
我已经为我的TCP服务器重新实现了来自Learn You Some Erlang的sockserv示例,但是我很难确定UDP的类似模型。
答案 0 :(得分:3)
对于a):
您需要对gen_server
行为进行delcare并实现所有回调函数(这很明显,但它值得明确调用)。如果安装了rebar
,则可以使用命令rebar create template=simplesrv srvid=your_server_name
添加样板函数。
您可能希望将服务器启动业务逻辑(gen_udp:open/2
调用)移至服务器的init/1
功能。 (gen_server
行为需要初始化。您也可以在那里启动loop/1
功能。
您可能希望确保模块的terminate/2
功能关闭了udp服务器。
将处理来自解析消息的请求的业务逻辑移动到您的loop/1
函数中,移动到模块中的handle_call/3
或handle_cast/2
(见下文)。
对于b):
您有几个选项,但基本上,每当您收到消息时,您都可以使用gen_server:cast/2
(如果您不关心响应)或gen_server:call/2,3
(如果您这样做)。演员表或电话将由您模块中的handle_cast/2
或handle_call/3
函数处理。
强制转换本质上是非阻塞的,this question的答案具有良好的设计模式,可以在gen_servers
中异步处理调用操作。你可以从中受益。