EMQXソースコード分析--- esockd_supモジュールのソースコード分析

esockd_supモジュールの動作モードはスーパーバイザーです。これはスーパーバイザーです。モジュールはesockd_appモジュール内のstart(_StartType、_StartArgs)メソッドによって内部的に呼び出され、次にesockd_sup内で次のメソッドが呼び出されます。

-spec(start_link() -> {ok, pid()} | ignore | {error, term()}).
start_link() ->
%%    io:format("esockd esockd_sup start_link ~n"),
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).
supervisor:start_link({local, ?MODULE}, ?MODULE, []). 方法会回到esockd_sup 内部的init方法,该方法如下:
init([]) ->
%%    io:format("esockd esockd_sup init ~n"),
    Limiter = #{id => rate_limiter, start => {esockd_rate_limiter, start_link, []},
    restart => permanent, shutdown => 5000, type => worker, modules [esockd_rate_limiter]},
    Server = #{id => esockd_server, start => {esockd_server, start_link, []}, 
    restart => permanent, shutdown => 5000, type => worker, modules  => [esockd_server]},
    {ok, {
   
   {one_for_one, 10, 100}, [Limiter, Server]}}.

以下のモジュール全体のコードを、上記の詳細な説明とともに貼り付けます。

%% Copyright (c) 2018 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.

-module(esockd_sup).

%% 声明该模块是监督者行为
-behaviour(supervisor).

%% 导出接口给外部模块调动
-export([start_link/0, child_id/2]).
-export([start_listener/4, stop_listener/2, restart_listener/2]).
-export([listeners/0, listener/1]).
-export([child_spec/4, udp_child_spec/4, dtls_child_spec/4, start_child/1]).

%% supervisor callback
-export([init/1]).

%%------------------------------------------------------------------------------
%% API
%%------------------------------------------------------------------------------

-spec(start_link() -> {ok, pid()} | ignore | {error, term()}).
start_link() ->
%%    io:format("esockd esockd_sup start_link ~n"),
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

-spec(start_listener(atom(), esockd:listen_on(), [esockd:option()], esockd:mfargs()) -> {ok, pid()} | {error, term()}).
start_listener(Proto, ListenOn, Opts, MFA) ->
%%    io:format("esockd_sup start_listener ~w~n",[Proto]), echo
%%    io:format("esockd_sup start_listener ~w~n",[ListenOn]),%% 5000
%%    io:format("esockd_sup start_listener ~w~n",[Opts]), %% [{acceptors,10},{max_connections,1024},{tcp_options,[binary,{reuseaddr,true}]}]
%%    io:format("esockd_sup start_listener ~w~n",[MFA]), %% {echo_server,start_link,[]}
    start_child(child_spec(Proto, ListenOn, Opts, MFA)).

-spec(child_spec(atom(), esockd:listen_on(), [esockd:option()], esockd:mfargs()) -> supervisor:child_spec()).
child_spec(Proto, ListenOn, Opts, MFA) when is_atom(Proto) ->
%%  Id 子进程ID标识符
%%  start:StartFunc = {M, F, A}: 子程序启动入口 M=esockd_listener_sup,F=start_link,A = [Proto, ListenOn, Opts, MFA]

%%  Restart: 重启方案
%%  1、permanent: 如果app终止了,整个系统都会停止工作(application:stop/1除外)
%%  2、transient: 如果app以normal的原因终止,没有影响。任何其它终止原因都谁导致整个系统关闭
%%  3、temporary: app可以以任何原因终止。只产生报告,没有其它任何影响

%%  shutdown:终止策略
%%  1、brutal_kill: 无条件终止
%%  2、超时值(毫秒): 终止时,如果超时,则强制终止
%%  3、infinity: 如果子进程是监控树,设置为无限大,等待其终止为止

%%  type
%%  1、worker: 普通子进程
%%  2、supervisor: 子进程是监控树

%%  Modules:
%%  dynamic: 当子进程是gen_event
%%  [Module]: 当子进程是监控树、gen_server或者gen_fsm,表示回调模块名称
    #{id => child_id(Proto, ListenOn), start => {esockd_listener_sup, start_link, [Proto, ListenOn, Opts, MFA]},
      restart => transient, shutdown => infinity, type => supervisor, modules => [esockd_listener_sup]}.

-spec(udp_child_spec(atom(), esockd:listen_on(), [esockd:option()], esockd:mfargs()) -> supervisor:child_spec()).
udp_child_spec(Proto, Port, Opts, MFA) when is_atom(Proto) ->
    #{id => child_id(Proto, Port), start => {esockd_udp, server, [Proto, Port, Opts, MFA]},
      restart => transient, shutdown => 5000, type => worker, modules => [esockd_udp]}.

-spec(dtls_child_spec(atom(), esockd:listen_on(), [esockd:option()], esockd:mfargs()) -> supervisor:child_spec()).
dtls_child_spec(Proto, Port, Opts, MFA) when is_atom(Proto) ->
    #{id => child_id(Proto, Port), start => {esockd_dtls_listener_sup, start_link, [Proto, Port, Opts, MFA]},
      restart => transient, shutdown => infinity, type => supervisor, modules => [esockd_dtls_listener_sup]}.

%% 启动子进程
-spec(start_child(supervisor:child_spec()) -> {ok, pid()} | {error, term()}).
start_child(ChildSpec) ->
	supervisor:start_child(?MODULE, ChildSpec).

%% 停止指定的服务监听
-spec(stop_listener(atom(), esockd:listen_on()) -> ok | {error, term()}).
stop_listener(Proto, ListenOn) ->
%%  获取匹配的监听者
    case match_listeners(Proto, ListenOn) of
%%      如果返回是空的,就说明没有找到
        [] -> {error, not_found};
%%      返回监听者数组
        Listeners ->
            return_ok_or_error([terminate_and_delete(ChildId) || ChildId <- Listeners])
    end.

%% 终止子进程
terminate_and_delete(ChildId) ->
	case supervisor:terminate_child(?MODULE, ChildId) of
%%    删除掉子进程
        ok    -> supervisor:delete_child(?MODULE, ChildId);
        Error -> Error
	end.

%% 获取listener_sup模块下的所有子进程,然后返回一个数组
-spec(listeners() -> [{term(), pid()}]).
listeners() ->
    [{Id, Pid} || {
   
   {listener_sup, Id}, Pid, _Type, _} <- supervisor:which_children(?MODULE)].

%% 获取一个指定的子进程
-spec(listener({atom(), esockd:listen_on()}) -> undefined | pid()).
listener({Proto, ListenOn}) ->
    ChildId = child_id(Proto, ListenOn),
%%        从该进程中寻找子进程,必须 Id =:= ChildId
    case [Pid || {Id, Pid, _Type, _} <- supervisor:which_children(?MODULE), Id =:= ChildId] of
%%      如果没有找到
        [] -> undefined;
%%      如果返回一个数组,从数组里去第一个元素
        L  -> hd(L)
    end.

%% 重新启动监听者
-spec(restart_listener(atom(), esockd:listen_on()) -> ok | {error, term()}).
restart_listener(Proto, ListenOn) ->
%%  获取匹配上的监听者
    case match_listeners(Proto, ListenOn) of
%%      如果没找到
        [] -> {error, not_found};
%%      如果找到了
        Listeners ->
%%          从Listeners内部去一个ChildId,然后执行terminate_and_restart(ChildId) 函数
            return_ok_or_error([terminate_and_restart(ChildId) || ChildId <- Listeners])
    end.

%% 终止并重启子进程
terminate_and_restart(ChildId) ->
%%  终止掉子进程
    case supervisor:terminate_child(?MODULE, ChildId) of
%%      如果终止掉了,然后就重启
        ok    -> supervisor:restart_child(?MODULE, ChildId);
%%      终止错误,就返回一个Error
        Error -> Error
    end.

%% 获取匹配的监听者,返回一个数组
match_listeners(Proto, ListenOn) ->
%%    从esockd_sup模块中获取该模块的子进程,然后执行match_listener 函数去匹配,如果返回true就加入到数组头部
    [ChildId || {ChildId, _Pid, _Type, _} <- supervisor:which_children(?MODULE), match_listener(Proto, ListenOn, ChildId)].

match_listener(Proto, ListenOn, {listener_sup, {Proto, ListenOn}}) ->
    true;
match_listener(Proto, Port, {listener_sup, {Proto, {_IP, Port}}}) ->
    true;
match_listener(_Proto, _ListenOn, _ChildId) ->
    false.

child_id(Proto, ListenOn) -> {listener_sup, {Proto, ListenOn}}.

return_ok_or_error([]) -> ok;
return_ok_or_error([ok|Results]) ->
    return_ok_or_error(Results);
return_ok_or_error([{ok, _Pid}|Results]) ->
    return_ok_or_error(Results);
return_ok_or_error([{error, Reason}|_]) ->
    {error, Reason}.

%%------------------------------------------------------------------------------
%% Supervisor callbacks
%%------------------------------------------------------------------------------

init([]) ->
%%    io:format("esockd esockd_sup init ~n"),
    Limiter = #{id => rate_limiter, start => {esockd_rate_limiter, start_link, []}, restart => permanent, shutdown => 5000, type => worker, modules => [esockd_rate_limiter]},
    Server = #{id => esockd_server, start => {esockd_server, start_link, []}, restart => permanent, shutdown => 5000, type => worker, modules  => [esockd_server]},
    {ok, {
   
   {one_for_one, 10, 100}, [Limiter, Server]}}.

このモジュールのinitメソッドのコールバックプロセスでは、esockd_rate_limiterとesockd_serverの2つのモジュールが開始されます。次に、esockd_rate_limiterモジュールを分析します。

おすすめ

転載: blog.csdn.net/qq513036862/article/details/87986665