直接上代码:( flash_policy_server )
-module(tcp_client).
-behaviour(gen_statem).
-export([start_link/0, set_socket/2,callback_mode/0]).
-export([init/1, handle_event/4,terminate/3, code_change/4]).
-define(PACKET,0).
-define(PACKETTYPE,list).
start_link() ->
gen_statem:start_link(?MODULE, [], []).
set_socket(Pid, Socket) when is_pid(Pid), is_port(Socket) ->
gen_statem:cast(Pid, {socket_ready, Socket }).
init([]) ->
process_flag(trap_exit, true),
State = #{},
{ok, wait_for_socket , State}.
callback_mode() -> handle_event_function.
handle_event(cast,{socket_ready,Socket},wait_for_socket,_State) ->
inet:setopts(Socket, [?PACKETTYPE, {packet, ?PACKET}, {delay_send,false}, {active, once}]),
{next_state,wait_for_data,
#{socket => Socket, mode => connect },
{timeout,5000,{conn_timeout}}
};
handle_event(timeout,{conn_timeout},wait_for_data,State) ->
{stop,normal,State};
handle_event(info,{tcp, Socket, _Bin},wait_for_data,#{socket := Socket} = State) ->
gen_tcp:send(Socket," \0"),
{stop,normal,State};
handle_event(info,{tcp_error,_,_},_,State) ->
{stop, normal, State};
handle_event(info,{tcp_closed,_,_},_,State) ->
{stop, normal, State};
handle_event(info,_Event,_,State) ->
{stop, normal, State}.
terminate(_Reason, _StateName, _State) ->
ok.
code_change(_OldVsn, OldState, StateData, _Extra) ->
{ok,OldState,StateData}.
和gen_fsm的一些区别:
1. 没有 handle_info , handle_sync_event
2. init/1 返回值以CallbackMode 开始
OTP 19.1 以后,init 返回还原成 { ok,StateName,StateData }
3. code_change/4 返回值也是以 CallbackMode 开始
OTP 19.1 以后,code_change/4 返回还原成 {ok,OldState,StateData}
4. 增加 call cast ,代替 gen_fsm:send_event
5. StateData 可以使用任何数据结构
gen_statem 支持两种回调模式:
1. state_functions :和gen_fsm类似,自定义函数来完成状态传递。
2. handle_event_function : 使用handle_event完成状态传递,个人觉得这种模式比较好,不用定义一些乱七八糟的函数,让代码更整齐。
关于handle_event
gen_statem:call(Pid,{start}) .
对应回调 handle_event(call,{start},StateName,StateData)
gen_statem:cast(Pid,{start}.
对应回调 handle_event(cast,{start},StateName,StateData)
Pid ! {start} (常见socket收到消息)
对应回调 handle_event(info,{start},StateName,StateData)
和 gen_fsm 的 handle_info 类似
关于 handle_event_result
如果状态保持不变,可以使用 {keep_state ,StateData}
如果状态和数据都不变,可以使用 {keep_state_and_data}
这个比gen_fsm每次都调用 next_state 方便多了
关于Timeout
{next_state,StateName,StateData,Action}
现在设置timeout放在action里面,格式 {timeout,N,{timeout_type}}
这个 {timeout_type} 将传递给
handle_event(timeout,{timeout_type},StataName,StateData)
还有一些特性还没有去研究,总之gen_statem很不错,建议把gen_fsm都替换成gen_statem。而且性能上应该有所提高。