Erlang OTP UDP 服务器

Myl*_*ell 5 erlang udp

这是一个简单的 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 的类似模型。

det*_*000 4

为一个):

  1. 您需要取消gen_server行为并实现所有回调函数(这是显而易见的,但值得显式调用)。如果已经rebar安装,可以使用命令rebar create template=simplesrv srvid=your_server_name添加样板函数。

  2. 您可能希望将服务器启动业务逻辑(调用gen_udp:open/2)移至服务器的init/1功能。(行为需要 init gen_server。您也可以loop/1在那里启动您的函数。

  3. 您可能想要确保 udp 服务器已被模块的terminate/2功能关闭。

  4. 将用于处理从解析消息到函数的请求的业务逻辑移至模块loop/1handle_call/3handle_cast/2模块中(见下文)。

对于b):您有几个选项,但基本上,每当您收到消息时,您都可以使用gen_server:cast/2(如果您不关心响应)或gen_server:call/2,3如果您这样做。转换或调用将由模块中的 handle_cast/2或函数处理。handle_call/3

强制转换本质上是非阻塞的,这个问题的答案有一个很好的设计模式,可以在gen_servers. 你可以从中抄袭。