【发布时间】:2011-12-28 21:50:02
【问题描述】:
我是 Erlang 初学者,正在尝试实现我的第一个 Erlang 应用程序。它是一个网络监控工具,应该对指定的主机执行 ping 请求。实际上发送ICMP不是目的,我对应用程序结构更感兴趣。目前我有monitor_app、monitor_sup(root sup)、pinger_sup 和pinger(worker)。这是 pinger_sup:
-module(pinger_sup).
-behaviour(supervisor).
-export([start_link/0, start_child/1, stop_child/1]).
-export([init/1]).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
start_child(Ip) ->
{ok, Pid} = supervisor:start_child(?MODULE, Ip),
put(Pid, Ip),
{ok, Pid}.
stop_child(Ip) ->
Children = get_keys(Ip),
lists:foreach(fun(Pid) ->
pinger:stop(Pid)
end,
Children).
init(_Args) ->
Pinger = {pinger, {pinger, start_link, []},
transient, 2000, worker, [pinger]},
Children = [Pinger],
RestartStrategy = {simple_one_for_one, 4, 3600},
{ok, {RestartStrategy, Children}}.
还有 pinger 本身:
-module(pinger).
-behaviour(gen_server).
-export([start_link/1, stop/1, stop_ping/1, ping/1, ping/2]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-define(PING_INTERVAL, 5000).
start_link(Ip) ->
gen_server:start_link(?MODULE, Ip, []).
stop(Pid) ->
gen_server:cast(Pid, stop).
stop_ping(Ip) ->
pinger_sup:stop_child(Ip).
ping(Ip) ->
pinger_sup:start_child(Ip).
ping(_Ip, 0) ->
ok;
ping(Ip, NProc) ->
ping(Ip),
ping(Ip, NProc - 1).
init(Ip) ->
erlang:send_after(1000, self(), do_ping),
{ok, Ip}.
handle_call(_Request, _From, State) ->
{noreply, State}.
handle_cast(stop, State) ->
io:format("~p is stopping~n", [State]),
{stop, normal, State}.
handle_info(do_ping, State) ->
io:format("pinging ~p~n", [State]),
erlang:send_after(?PING_INTERVAL, self(), do_ping),
{noreply, State};
handle_info(Info, State) ->
io:format("Unknown message: ~p~n", [Info]),
{noreply, State}.
terminate(_Reason, State) ->
io:format("~p was terminated~n", [State]),
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
它缺少 cmets,但我认为它对任何 Erlang 开发人员来说都非常简单和熟悉。我对这段代码有几个问题:
1) init 中的 *erlang:send_after* 是一个好的解决方案吗?如果我需要进程立即开始执行工作而不从外部触发他的功能,那么最佳做法是什么?
2) 目前我使用 pinger:ping("127.0.0.1"). 命令启动 ping。 pinger 模块要求 pinger_sup 启动子进程。该过程开始后,我想停止它。最好的方法是什么?我应该通过 sup 终止它还是应该向他发送停止命令?我应该如何存储进程PID?目前我使用进程字典,但在实现它之后,我意识到字典实际上不属于 sup (它是一个 shell 字典或任何其他 stop_child 调用者)。如果我使用 ETS 并且 sup 被终止,这些死进程 PID 会永远留在 ETS 中导致某种内存泄漏吗?
感谢任何答案和代码 cmets。
谢谢!
【问题讨论】:
标签: erlang