简体   繁体   English

rebar3,主管,行为(应用程序)

[英]rebar3, supervisor, behaviour(application)

I have the following straightforward UDP Server:我有以下简单的 UDP 服务器:

  • ONLY accept Binary <<0:32>>,只接受二进制 <<0:32>>,

  • otherwise it crash否则它会崩溃

     -module(server). -export([listen/1]). listen(Port) -> spawn(fun()->run_it(Port) end). run_it(Port) -> {ok, Skt} = gen_udp:open(Port, [binary]), loop(Skt). loop(Skt) -> receive {udp, Skt, _, _, Bin} -> case Bin of <<0:32>> -> io:fwrite("~p~n", [{"Good Format: ", Bin}]), loop(Skt) end end.

Now, my peer UDP Client is going to send a malformed data intentionally.现在,我的同行 UDP 客户端将故意发送格式错误的数据。

I can write a case clause to match any message and simply ignore any malformed message.我可以编写一个 case 子句来匹配任何消息,而忽略任何格式错误的消息。

However, it will not help me if there is eventual bugs.但是,如果最终出现错误,它将无济于事。

I have read somewhere: "Don't program defensively, let it crash, then fix it".我在某处读过:“不要防御性地编程,让它崩溃,然后修复它”。

    =ERROR REPORT==== 19-Jul-2020::21:15:29.872000 ===
    Error in process <0.93.0> with exit value:
    {{case_clause,<<0>>},[{server,loop,1,[{file,"server.erl"},{line,16}]}]}

Cool, it crash, But I want my server to restart automatically now:-)酷,它崩溃了,但我希望我的服务器现在自动重启:-)

I have read that a process called "supervisor" can monitor my server and restarts it when it detects that it died.我读过一个名为“supervisor”的进程可以监视我的服务器并在检测到它死亡时重新启动它。

So, I have used "rebar3" because it helped me a lot when I compile several files with just 1 single line 'rebar3 compile'.所以,我使用了“rebar3”,因为当我只用 1 行“rebar3 compile”编译多个文件时,它对我有很大帮助。

It creates automatically a /src/ with 3 files, but only 2 are interesting me for now:它会自动创建一个带有 3 个文件的 /src/ ,但我现在只对 2 个文件感兴趣:

  • server_app.erl server_app.erl
  • server_sup.erl server_sup.erl

In addition, I have read the documentations but I'm still far from understanding.另外,我已经阅读了文档,但我仍然远未理解。

Can anyone advise please, or transform my 19 lines of code server.erl to server_app.erl and supervised by a server_sup.erl ?谁能提供建议,或者将我的 19 行代码server.erl转换为server_app.erl并由server_sup.erl监督?

NB: I'm not looking for a gen_server, I see it a lot but am I obligated to transform this to a gen_server also, or only application+supervisor is ok for my requirement?注意:我不是在寻找 gen_server,我经常看到它,但我是否也有义务将其转换为 gen_server,或者只有 application+supervisor 可以满足我的要求?

Thanks in advance,提前致谢,

Best Regards,此致,

Supervisors are part of the OTP supervision tree, which handles all the restart policies and such.监督者是 OTP 监督的一部分,它处理所有重启策略等。 Although it's possible not to use gen_servers for its modules, I'd avise against it: gen_servers provide a handy abstraction for the most common server operations (and they handle name registering , sys messages and other goodies out of the box).虽然它的模块可以不使用gen_servers ,但我反对它: gen_servers 为最常见的服务器操作提供了一个方便的抽象(它们处理名称注册sys消息和其他开箱即用的好东西)。

Although the 'let it crash' lemma is common in Erlang, it does not mean that you don't have to foresee issues your code may face or that you only care about the happy case.尽管“让它崩溃”引理在 Erlang 中很常见,但这并不意味着您不必预见代码可能面临的问题,或者您只关心幸福的情况。 I'd hate to see any sytem crashing due to someone's malformed/malicious nc -u .我不想看到任何系统由于某人的格式错误/恶意nc -u而崩溃。

Keep in mind that if the supervisor's restart limit is reached, it will die too, eventually reaching the application's top supervisor, which crashes the VM upon death.请记住,如果达到主管的重启限制,它也会死亡,最终到达应用程序的顶级主管,这会在死亡时使 VM 崩溃。

Let's get to the code (very little editing over what rebar3 new app generates):让我们来看看代码(对rebar3 new app生成的内容几乎没有编辑):

The application requires no editions:该应用程序不需要任何版本:

-module(server_app).

-behaviour(application).
-export([start/2, stop/1]).

start(_StartType, _StartArgs) ->
    server_sup:start_link().

stop(_State) ->
    ok.

The supervisor has a little more configuration, but that's it:主管有更多的配置,但就是这样:

-module(server_sup).

-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).

start_link() ->
    supervisor:start_link(?MODULE, []).

init([]) ->
    SupFlags = #{strategy => one_for_all,
                 intensity => 0,
                 period => 1},
    ChildSpecs = [#{id => my_server,
                    start => {server, start_link, [12345]},
                    type => worker
                   }],
    {ok, {SupFlags, ChildSpecs}}.

And the server.erl needs some modifications in the start function:server.erl需要在启动function中进行一些修改:

-module(server).
-export([start_link/1]).

start_link(Port) ->
    {ok, spawn_link(fun()->run_it(Port) end)}.

run_it(Port) ->
    {ok, Skt} = gen_udp:open(Port, [binary]),
    loop(Skt).

loop(Skt) ->
    receive
        {udp, Skt, _, _, Bin} ->
            case Bin of
                <<0:32>> ->
                    io:fwrite("~p~n", [{"Good Format: ", Bin}]),
                    loop(Skt)
            end

The server.erl as gen_server would be something like: server.erl作为gen_server将类似于:

-module(server).

-export([start_link/1]).

-behaviour(gen_server).
-export([
         init/1,
         handle_cast/2,
         handle_call/3,
         handle_info/2
        ]).

start_link(Port) ->
    gen_server:start_link(?MODULE, Port, []).

init(Port) ->
    gen_udp:open(Port, [binary]).

handle_call(_Call, _From, State) ->
    {reply, ok, State}.

handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info({udp, Skt, _, _, Bin}, Skt) ->
    case Bin of
        <<0:32>> -> io:fwrite("~p~n", [{"Good Format: ", Bin}])
    end,
    {noreply, Skt};
handle_info(_Msg, State) -> % Messages that are not {udp, Skt, _, _, _} are discarded
    {noreply, State}.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM