[英]rebar3, supervisor, behaviour(application)
我有以下简单的 UDP 服务器:
只接受二进制 <<0:32>>,
否则它会崩溃
-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.
现在,我的同行 UDP 客户端将故意发送格式错误的数据。
我可以编写一个 case 子句来匹配任何消息,而忽略任何格式错误的消息。
但是,如果最终出现错误,它将无济于事。
我在某处读过:“不要防御性地编程,让它崩溃,然后修复它”。
=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}]}]}
酷,它崩溃了,但我希望我的服务器现在自动重启:-)
我读过一个名为“supervisor”的进程可以监视我的服务器并在检测到它死亡时重新启动它。
所以,我使用了“rebar3”,因为当我只用 1 行“rebar3 compile”编译多个文件时,它对我有很大帮助。
它会自动创建一个带有 3 个文件的 /src/ ,但我现在只对 2 个文件感兴趣:
另外,我已经阅读了文档,但我仍然远未理解。
谁能提供建议,或者将我的 19 行代码server.erl转换为server_app.erl并由server_sup.erl监督?
注意:我不是在寻找 gen_server,我经常看到它,但我是否也有义务将其转换为 gen_server,或者只有 application+supervisor 可以满足我的要求?
提前致谢,
此致,
监督者是 OTP 监督树的一部分,它处理所有重启策略等。 虽然它的模块可以不使用gen_servers ,但我反对它: gen_servers 为最常见的服务器操作提供了一个方便的抽象(它们处理名称注册、 sys消息和其他开箱即用的好东西)。
尽管“让它崩溃”引理在 Erlang 中很常见,但这并不意味着您不必预见代码可能面临的问题,或者您只关心幸福的情况。 我不想看到任何系统由于某人的格式错误/恶意nc -u
而崩溃。
请记住,如果达到主管的重启限制,它也会死亡,最终到达应用程序的顶级主管,这会在死亡时使 VM 崩溃。
让我们来看看代码(对rebar3 new app
生成的内容几乎没有编辑):
该应用程序不需要任何版本:
-module(server_app).
-behaviour(application).
-export([start/2, stop/1]).
start(_StartType, _StartArgs) ->
server_sup:start_link().
stop(_State) ->
ok.
主管有更多的配置,但就是这样:
-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}}.
而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
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.