emqx私有tcp协议服务器开发---emqx_tcp_connection模块(2)

接着上一篇,继续分析下面的代码 

%% 速率限制未定义返回
rate_limit_info(undefined) -> #{};
%% 调用esockd 库函里面的方法获取限速相关信息
rate_limit_info(Limit) -> esockd_rate_limit:info(Limit).

%% 通过进程id 获取进程的统计信息
stats(CPid) when is_pid(CPid) -> call(CPid, stats);
stats(#state{transport = Transport, socket = Socket,pstate = PState}) ->
    SockStats = case Transport:getstat(Socket,
                                       [recv_oct, %% 接收字节数
                                        recv_cnt, %% 接收消息条数
                                        send_oct, %% 发送字节数
                                        send_cnt, %% 发送消息条数
                                        send_pend])
                    of
                    {ok, Ss} -> Ss;
                    {error, _} -> []
                end,
    %% 收集相关的统计统计信息返回
    lists:append([SockStats,
                  emqx_misc:proc_stats(),
                  emqx_tcp_protocol:stats(PState)]).

kick(CPid) -> call(CPid, kick).

call(CPid, Req) -> gen_statem:call(CPid, Req, infinity).

%% 连接服务进程初始化
init({Transport, RawSocket, Options}) ->
    %% 等待socket连接
    case Transport:wait(RawSocket) of
        %% 返回连接,然后进行初始化
        {ok, Socket} -> do_init(Transport, Socket, Options);
        %% 错误,然后关闭socket
        {error, Reason}
            when Reason =:= enotconn;
                 Reason =:= einval;
                 Reason =:= closed ->
            Transport:fast_close(RawSocket),
            exit(normal);
        %% 超时,然后关闭
        {error, timeout} ->
            Transport:fast_close(RawSocket),
            exit({shutdown, ssl_upgrade_timeout});
        %% 其他原因,关闭
        {error, Reason} ->
            Transport:fast_close(RawSocket),
            exit(Reason)
    end.

%% 客户端socket连接初始化
do_init(Transport, Socket, Options) ->
    %% 确保该连接之前的连接退出
    {ok, Peername} = Transport:ensure_ok_or_exit(peername,
                                                 [Socket]),
    {ok, Sockname} = Transport:ensure_ok_or_exit(sockname,
                                                 [Socket]),
    Peercert = Transport:ensure_ok_or_exit(peercert,
                                           [Socket]),
    
    emqx_logger:set_metadata_peername(esockd:format(Peername)),
    %% 获取限速信息
    RateLimit = init_limiter(proplists:get_value(rate_limit,Options)),
    %% 一次性从内核读多少数据包
    ActiveN = proplists:get_value(active_n, Options, 100),
    %% 发送函数定义
    SendFun = fun (Packet, Opts) ->
                      %% 序列号数据包
                      Data = emqx_tcp_frame:serialize(Packet, Opts),
                      %% 异步发送数据包
                      case Transport:async_send(Socket, Data) of
                          ok -> {ok, Data};
                          {error, Reason} -> {error, Reason}
                      end
              end,
    %% 连接信息封装
    ConnInfo = #{socktype => Transport:type(Socket),
                 peername => Peername, sockname => Sockname,
                 peercert => Peercert, sendfun => SendFun,
                 conn_mod => emqx_tcp_connection},
    %% 初始化PState
    PState = emqx_tcp_protocol:init(ConnInfo, Options),
    %% 数据报最大设置
    MaxSize = proplists:get_value(max_packet_size,Options, 65535),
                                  
    
    %% 数据解析状态初始化                             
    ParseState = emqx_tcp_frame:initial_parse_state(#{max_size => MaxSize}),
       
    %% 统计配置是否开启                                            
    EnableStats = proplists:get_value(enable_stats,Options,true),
    %% 空闲超时设置
    IdleTimout = proplists:get_value(idle_timeout,Options,30000),                                 
    %% 客户端socket状态封装                                                                  
    State = #state{transport = Transport, socket = Socket,
                   peername = Peername, sockstate = running,
                   active_n = ActiveN, rate_limit = RateLimit,
                   pstate = PState, parse_state = ParseState,
                   enable_stats = EnableStats, idle_timeout = IdleTimout},

    %% 进入客户端socket进程循环
    gen_statem:enter_loop(emqx_tcp_connection,
                          [{hibernate_after, 2 * IdleTimout}],
                          idle,State,self(),[IdleTimout]).

%% 限速设置
init_limiter(undefined) -> undefined;
init_limiter({Rate, Burst}) ->esockd_rate_limit:new(Rate, Burst).

%% 回调	
callback_mode() -> [state_functions, state_enter].

idle(enter, _, State) ->
    ok = activate_socket(State),
    keep_state_and_data;
idle(timeout, _Timeout, State) ->
    {stop, {shutdown, idle_timeout}, State};
idle(cast, {incoming, Packet}, State) ->
    handle_incoming(Packet,
                    fun (NState) -> {next_state, connected, NState} end,
                    State);
idle(EventType, Content, State) ->
    handle(EventType, Content, State).

%% 连接进入
connected(enter, _, _State) -> keep_state_and_data;
%% 异步处理进来的数据包
connected(cast, {incoming, Packet}, State) ->
    %%处理进来的数据包
    handle_incoming(Packet,fun (NState) -> {keep_state, NState} end, State);
%% 处理消息投递          
connected(info, {deliver, _Topic, Message},State = #state{pstate = PState}) ->
          
    case emqx_tcp_protocol:deliver({message, Message},PState) of
        {ok, NPState} ->
            NState = State#state{pstate = NPState},
            {keep_state, NState};
        {error, Reason} -> shutdown(Reason, State)
    end;
%% 处理keepalive
connected(info, {keepalive, start, Interval}, State) ->
    Keepalive = emqx_keepalive:init(Interval),
    %% 启动定时
    _ = emqx_misc:start_timer(Interval, {keepalive, check}),
    {keep_state, State#state{keepalive = Keepalive}};
connected(EventType, Content, State) ->
    handle(EventType, Content, State).

猜你喜欢

转载自blog.csdn.net/qq513036862/article/details/110310430