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

前の記事で述べたように、ok = esockd:start()を実行した後、アプリケーションはそれぞれesockd_sup、esockd_rate_limiter、esockd_serverの3つのモジュールを起動します。これら3つのモジュールを起動した後、独自のソケットサービスを挿入する必要があります。ここではecho_serverを使用します。例として、シェルで実行された場合

esockd:open(echo, 5000, Options, MFArgs).

esockd_supモジュールの次のメソッドが呼び出されます。

esockd_sup:start_listener(Proto, Port, Opts, MFA);

次に、start_listener(Proto、ListenOn、Opts、MFA)メソッドが内部的に呼び出されます。

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

esockd_supのリスナーモジュールで子プロセスを開始します。この子プロセスの仕様は次のとおりです。

-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]}.

子プロセスを開始するメソッドが実行された後、esockd_listener_supモジュールのstart_link(Proto、ListenOn、Opts、MFA)メソッドが実行され、内部呼び出しの実行プロセスが以下のソースコードコメントに示されます。

-module(esockd_listener_sup).

-behaviour(supervisor).

-include("esockd.hrl").

-export([start_link/4, listener/1, acceptor_sup/1, connection_sup/1]).

%% export for dtls_listener_sup
-export([rate_limit_fun/2]).

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

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

%% @doc Start listener supervisor
-spec(start_link(atom(), esockd:listen_on(), [esockd:option()], esockd:mfargs()) -> {ok, pid()} | {error, term()}).
start_link(Proto, ListenOn, Opts, MFA) ->
%%    io:format("esockd_listener_sup start() ~n"),
    {ok, Sup} = supervisor:start_link(?MODULE, []),
    %% Start connection sup
    ConnSupSpec = #{id => connection_sup, start => {esockd_connection_sup, start_link, [Opts, MFA]}, restart => transient, shutdown => infinity, type => supervisor, modules => [esockd_connection_sup]},

%%    io:format("esockd_listener_sup start() ConnSupSpec ~w~n",[ConnSupSpec]),
%%    esockd_listener_sup 监控树下 启动esockd_connection_sup 连接监听
    {ok, ConnSup} = supervisor:start_child(Sup, ConnSupSpec),
%%   io:format("esockd_listener_sup supervisor:start_child(?,?) ~w~n",[ConnSupSpec]),
%%  #{id => connection_sup,modules => [esockd_connection_sup],restart => transient,shutdown => infinity,
%%  start => {esockd_connection_sup,start_link,[[{acceptors,10},{max_connections,1024},{tcp_options,[binary,{reuseaddr,true}]}],
%% {echo_server,start_link,[]}]},type => supervisor}

%% Start acceptor sup
    TuneFun = buffer_tune_fun(Opts),
    UpgradeFuns = upgrade_funs(Opts),
    StatsFun = esockd_server:stats_fun({Proto, ListenOn}, accepted),
    LimitFun = rate_limit_fun({listener, Proto, ListenOn}, Opts),
%%    io:format("esockd_listener_sup start_link TuneFun ~w~n",[TuneFun]),
%%    io:format("esockd_listener_sup start_link UpgradeFuns ~w~n",[UpgradeFuns]),
%%    io:format("esockd_listener_sup start_link LimitFun ~w~n",[LimitFun]),

    %% esockd_listener_sup 监控树下 启动esockd_acceptor_sup 接收连接请求监听
    AcceptorSupSpec = #{id => acceptor_sup, start => {esockd_acceptor_sup, start_link, [ConnSup, TuneFun, UpgradeFuns, StatsFun, LimitFun]},
                        restart => transient, shutdown => infinity, type => supervisor, modules => [esockd_acceptor_sup]},

    {ok, AcceptorSup} = supervisor:start_child(Sup, AcceptorSupSpec),
    %% Start listener
    ListenerSpec = #{id => listener, start => {esockd_listener, start_link, [Proto, ListenOn, Opts, AcceptorSup]}, restart => transient,
      shutdown => 16#ffffffff, type => worker, modules => [esockd_listener]},

%%  esockd_listener_sup 监控树下 启动esockd_listener
    {ok, _Listener} = supervisor:start_child(Sup, ListenerSpec),
    {ok, Sup}.

%% @doc Get listener.
-spec(listener(pid()) -> pid()).
listener(Sup) -> child_pid(Sup, listener).

%% @doc Get connection supervisor.
-spec(connection_sup(pid()) -> pid()).
connection_sup(Sup) -> child_pid(Sup, connection_sup).

%% @doc Get acceptor supervisor.
-spec(acceptor_sup(pid()) -> pid()).
acceptor_sup(Sup) -> child_pid(Sup, acceptor_sup).

%% @doc Get child pid with id.
child_pid(Sup, ChildId) ->
    hd([Pid || {Id, Pid, _, _}
               <- supervisor:which_children(Sup), Id =:= ChildId]).

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

init([]) ->
%%     io:format("esockd_listener_sup init() ~n"),
    {ok, {
   
   {rest_for_one, 10, 3600}, []}}.

%%------------------------------------------------------------------------------
%% Sock tune/upgrade functions
%%------------------------------------------------------------------------------

buffer_tune_fun(Opts) ->
    buffer_tune_fun(proplists:get_value(buffer, Opts),
                    proplists:get_bool(tune_buffer, Opts)).

%% when 'buffer' is undefined, and 'tune_buffer' is enabled...
buffer_tune_fun(undefined, true) ->
    fun(Sock) ->
        case inet:getopts(Sock, [sndbuf, recbuf, buffer]) of
            {ok, BufSizes} ->
                BufSz = lists:max([Sz || {_Opt, Sz} <- BufSizes]),
                inet:setopts(Sock, [{buffer, BufSz}]),
                {ok, Sock};
            Error -> Error
        end
    end;
buffer_tune_fun(_, _) ->
    fun(Sock) -> {ok, Sock} end.

upgrade_funs(Opts) ->
    lists:append([ssl_upgrade_fun(Opts), proxy_upgrade_fun(Opts)]).

ssl_upgrade_fun(Opts) ->
    case proplists:get_value(ssl_options, Opts) of
        undefined -> [];
        SslOpts   -> [esockd_transport:ssl_upgrade_fun(SslOpts)]
    end.

proxy_upgrade_fun(Opts) ->
    case proplists:get_bool(proxy_protocol, Opts) of
        false -> [];
        true  -> [esockd_transport:proxy_upgrade_fun(Opts)]
    end.

rate_limit_fun(Bucket, Opts) ->
    case proplists:get_value(max_conn_rate, Opts) of
        undefined ->
            fun(_) -> {1, 0} end;
        I when is_integer(I) ->
            rate_limit_fun(Bucket, I, 1);
        {Limit, Period} ->
            rate_limit_fun(Bucket, Limit, Period)
    end.

rate_limit_fun(Bucket, Limit, Period) ->
%%    io:format("esockd_listener_sup rate_limit_fun() Bucket ~w~n",[Bucket]),
%%    io:format("esockd_listener_sup rate_limit_fun() Limit ~w~n",[Limit]),
%%    io:format("esockd_listener_sup rate_limit_fun() Period ~w~n",[Period]),
    ok = esockd_rate_limiter:create(Bucket, Limit, Period),
    fun(I) -> esockd_rate_limiter:consume(Bucket, I) end.



%% ok = esockd:start().
%% Options = [{acceptors, 1}, {max_connections, 1024}, {tcp_options, [binary, {reuseaddr, true}]}].
%% MFArgs = {echo_server, start_link, []},esockd:open(echo, 5000, Options1, MFArgs).

このモジュールのstart_link(Proto、ListenOn、Opts、MFA)は、esockd_listener_sup監視モジュール、esockd_acceptor_sup監視モジュール、およびesockd_listenerワーカーモジュールを開始します。これまでのところ、シェルで実行できます。

observer:start().

最後のコマンドを実行して、次のようにプロセス構造図を取得します。

プロセス<0.101.0>:esockd_listener_supプロセスの開始<0.102.0>:esockd_connection_sup

プロセス<0.101.0>:esockd_listener_supプロセスの開始<0.103.0>:esockd_acceptor_sup

プロセス<0.103.0>:esockd_acceptor_supプロセスの開始<0.105.0>:esockd_acceptor

プロセス<0.101.0>:esockd_listener_supプロセスの開始<0.104.0>:esockd_listener

このノードに対してプログラムが実行され、サーバーの基本ノードが起動され、クライアントプロセスのtcp接続を待機してから、esockd_connection_supモジュールが分析されます。

おすすめ

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