-module(emqx_tcp_protocol).
-export([logger_header/0]).
-include("emqx_tcp/include/emqx_tcp.hrl").
-include("emqx/include/emqx.hrl").
-include("/emqx/include/logger.hrl").
-import(proplists, [get_value/2]).
-import(emqx_misc, [maybe_apply/2]).
-export([init/2,received/2,
deliver/2,terminate/2,maybe_gc_and_check_oom/2]).
-export([info/1, client_id/1, stats/1]).
-record(pstate,
{peername,
sockname,
peercert,
client_id,
username,
keepalive,
sendfun, %% 发送函数
conn_pid, %% 连接进程ID
connected = false,
up_topic, %% 上行主题
dn_topic, %% 下行主题
proto_ver,%% 协议版本
conn_mod, %% 连接模块
connected_at, %% 连接时间
gc_state, %% gc状态
recv_stats, %% 接收统计
send_stats}). %% 发送统计
-vsn("4.2.1").
%% 初始化
init(SocketOpts = #{sockname := Sockname,peername := Peername, peercert :=
Peercert,sendfun := SendFun},Options) ->
#pstate{sockname = Sockname, peername = Peername,
peercert = Peercert,
up_topic = get_value(up_topic, Options),
dn_topic = get_value(dn_topic, Options),
conn_pid = self(), sendfun = SendFun,
gc_state = init_gc_state(),
conn_mod = maps:get(conn_mod, SocketOpts, undefined),
recv_stats = #{msg => 0, pkt => 0},
send_stats = #{msg => 0, pkt => 0}}.
%% gc状态初始化
init_gc_state() ->
%% 获取gc配置策略
GcPolicy = application:get_env(emqx_tcp,force_gc_policy,undefined),
maybe_apply(fun emqx_gc:init/1, GcPolicy).
%% 接收数据
received(Packet = #tcp_packet_conn{},PState = #pstate{connected = false}) ->
process(Packet, PState#pstate{connected = true});
%% 已经连接
received(#tcp_packet_conn{},PState = #pstate{connected = true}) ->
{error, protocol_has_connected, PState};
%% 未连接
received(_Packet,PState = #pstate{connected = false}) ->
{error, protocol_not_connected, PState};
received(Packet, PState) -> process(Packet, PState).
%% 处理连接数据包
process(#tcp_packet_conn{client_id = ClientId,keepalive = Keepalive, username =
Username, password = Password},PState) ->
PState1 = prepare_adapter_topic(PState#pstate{client_id = ClientId,username =
Username, keepalive = Keepalive,
connected_at =erlang:system_time(millisecond)}),
%% 客户端连接信息
ClientInfo = clientinfo(PState1),
%%
_ = run_hooks('client.connect', [conninfo(PState1)], undefined),
%%
connack(case emqx_access_control:authenticate(ClientInfo#{password =>Password}) of
{ok, _ClientInfo0} ->
emqx_logger:set_metadata_clientid(ClientId),
ok =
emqx_cm:register_channel(ClientId,info(PState1),stats(PState1)),
autosubcribe(PState1),
start_keepalive(Keepalive, PState1),
{0, PState1};
{error, Reason} ->
begin
logger:log(warning,
#{},
#{report_cb =>
fun (_) ->
{'$logger_header'() ++
"TCP Client ~s (Username: '~s') login "
"failed for ~p",
[ClientId, Username, Reason]}
end,
mfa => {emqx_tcp_protocol, process, 2},
line => 113})
end,
{1, <<"Authentication Failure">>, PState1}
end);
%% 处理业务数据包
process(Packet = #tcp_packet_datatrans{}, PState) ->do_publish(Packet, PState);
%% 处理ping,pong
process(#tcp_packet_ping{}, PState) ->deliver(pong, PState);
%% 处理断开连接数据包
process(#tcp_packet_disconn{}, PState) ->{stop, normal, PState};
%% 处理非法数据包
process(Packet, PState) ->{error, {unknown_packet, Packet}, PState}.
terminate(_Reason, #pstate{client_id = undefined}) -> ok;
terminate(_Reason, #pstate{connected = false}) -> ok;
terminate(Reason, PState) ->
begin
logger:log(info,
#{},
#{report_cb =>
fun (_) ->
{'$logger_header'() ++ "Shutdown for ~p",
[Reason]}
end,
mfa => {emqx_tcp_protocol, terminate, 2}, line => 134})
end,
ConnInfo = conninfo(PState),
ConnInfo1 = maps:put(disconnected_at,erlang:system_time(millisecond), ConnInfo),
ok = emqx_hooks:run('client.disconnected',[clientinfo(PState), Reason, ConnInfo1]).
emqx私有tcp协议服务器开发---emqx_tcp_protocol模块(1)
猜你喜欢
转载自blog.csdn.net/qq513036862/article/details/110313542
今日推荐
周排行