erlang高性能网络库esockd的编译和使用(三)-keepalive

来源:互联网 发布:女白色t恤淘宝店铺推荐 编辑:程序博客网 时间:2024/06/11 13:54

在上一篇基础上,继续完善app。新增心跳检测机制。

修改文件echo_server.erl如下:

-module(echo_server).-include("../deps/esockd/include/esockd.hrl").-behaviour(gen_server).%% start-export([start/0, start/1]).-export([start_link/1]).%% gen_server Function Exports-export([init/1, handle_call/3, handle_cast/2, handle_info/2,         terminate/2, code_change/3]).-record(state, {conn, connname, peername, peerhost, peerport, keepalive}).-define(TCP_OPTIONS, [binary,        {packet, raw},        {buffer, 1024},{reuseaddr, true},{backlog, 512},{nodelay, false}]).-define(TCP_PORT, 5000).-define(TIMEOUT_SEC, 30).%unit:s%% APIstart() ->    start(?TCP_PORT).start([Port]) when is_atom(Port) ->    start(list_to_integer(atom_to_list(Port)));start(Port) when is_integer(Port) ->    %% application:start(sasl),    %% ok = esockd:start(),    Access = application:get_env(esockd, access, [{allow, all}]),    SockOpts = [{access, Access},                {acceptors, 32},                {max_clients, 1000000},                {sockopts, ?TCP_OPTIONS}],    MFArgs = {?MODULE, start_link, []},    esockd:open(echo, Port, SockOpts, MFArgs).%% eSockd Callbacksstart_link(Conn) ->    {ok, proc_lib:spawn_link(?MODULE, init, [Conn])}.init(Conn) ->    {ok, Conn1} = Conn:wait(),    {PeerHost, PeerPort, PeerName} =    case Conn1:peername() of        {ok, Peer = {Host, Port}} ->            {Host, Port, Peer};        {error, enotconn} ->            Conn1:fast_close(),            exit(normal);        {error, Reason} ->            Conn1:fast_close(),            exit({shutdown, Reason})    end,    ConnName = esockd_net:format(PeerName),    %%io:format("~s~n", [esockd_net:format(peername, PeerName)]),    io:format("tcp_connected,~s~n", [esockd_net:format({PeerHost, PeerPort})]),    start_keepalive(?TIMEOUT_SEC),    Conn1:setopts([{active, once}]),    gen_server:enter_loop(?MODULE, [], #state{conn       = Conn1,                                              connname   = ConnName,                                              peername   = PeerName,                                              peerhost   = PeerHost,                                              peerport   = PeerPort}).    handle_call(_Request, _From, State) ->    {reply, ok, State}.handle_cast(_Msg, State) ->    {noreply, State}.handle_info({tcp, Sock, Data}, State = #state{conn = ?ESOCK(Sock) = Conn}) ->    {ok, PeerName} = Conn:peername(),    io:format("~s - ~s~n", [esockd_net:format(peername, PeerName), Data]),    Conn:send(Data),    Conn:setopts([{active, once}]),    {noreply, State};handle_info({tcp_error, Sock, Reason}, State = #state{conn = ?ESOCK(Sock)}) ->    io:format("tcp_error: ~s~n", [Reason]),    {stop, {shutdown, {tcp_error, Reason}}, State};handle_info({tcp_closed, Sock}, State = #state{conn = ?ESOCK(Sock), peername = PeerName}) ->    io:format("tcp_closed,~s~n", [esockd_net:format(peername, PeerName)]),    {stop, normal, State};handle_info({keepalive, start, Interval}, State = #state{conn = Conn1}) ->    io:format("Keepalive at the interval of ~p~n", [Interval]),    {ok, KeepAlive} = esockd_keepalive:start(Conn1, Interval, {keepalive, check}),    hibernate(State#state{keepalive = KeepAlive});handle_info({keepalive, check}, State = #state{peername = PeerName, keepalive = KeepAlive}) ->    io:format("Keepalive check,~s,", [esockd_net:format(peername, PeerName)]),    case esockd_keepalive:resume(KeepAlive) of        {resumed, KeepAlive1} ->            io:format("Keepalive resumed~n"),            hibernate(State#state{keepalive = KeepAlive1});        {error, timeout} ->            io:format("Keepalive timeout~n"),            shutdown(keepalive_timeout, State);        {error, Error} ->            io:format("Keepalive error - ~p~n", [Error]),            shutdown(Error, State)    end;handle_info(_Info, State) ->    {noreply, State}.%terminate(_Reason, _State) ->%    ok.terminate(_Reason, #state{conn     = Conn1,                         keepalive = KeepAlive}) ->    Conn1:fast_close(),    esockd_keepalive:cancel(KeepAlive),    ok.code_change(_OldVsn, State, _Extra) ->    {ok, State}.%%--------------------------------------------------------------------%% Internal functions%%--------------------------------------------------------------------start_keepalive(0) -> ignore;start_keepalive(Sec) when Sec > 0 ->    self() ! {keepalive, start, round(Sec * 1.20)}.hibernate(State) ->    {noreply, State, hibernate}.shutdown(Reason, State) ->    stop({shutdown, Reason}, State).stop(Reason, State) ->    {stop, Reason, State}.

如果想知道当前客户端的数目,可以在init函数实现:

init(Conn) ->    {ok, Conn1} = Conn:wait(),    {PeerHost, PeerPort, PeerName} =    case Conn1:peername() of        {ok, Peer = {Host, Port}} ->            {Host, Port, Peer};        {error, enotconn} ->            Conn1:fast_close(),            exit(normal);        {error, Reason} ->            Conn1:fast_close(),            exit({shutdown, Reason})    end,    ConnName = esockd_net:format(PeerName),    %%io:format("~s~n", [esockd_net:format(peername, PeerName)]),    io:format("tcp_connected,~s~n", [esockd_net:format({PeerHost, PeerPort})]),    start_keepalive(?TIMEOUT_SEC),    Conn1:setopts([{active, once}]),    %% method 1:    lists:foreach(fun({{Protocol, ListenOn}, Pid}) ->                Info = [{acceptors,      esockd:get_acceptors(Pid)},                        {max_clients,    esockd:get_max_clients(Pid)},                        {current_clients,esockd:get_current_clients(Pid)},                        {shutdown_count, esockd:get_shutdown_count(Pid)}],                io:format("listener on ~s:~s~n", [Protocol, esockd:to_string(ListenOn)]),                lists:foreach(fun({Key, Val}) ->                            io:format("  ~-16s: ~w~n", [Key, Val])                        end, Info)            end, esockd:listeners()),    %% method 2:    Pid1 = esockd:listener({echo, ?TCP_PORT}),    Count1 = esockd:get_current_clients(Pid1),    io:format("current_clients:~p~n", [Count1]),        %% method 3:    Count2 = esockd:get_current_clients({echo, ?TCP_PORT}),    io:format("current_clients:~p~n", [Count2]),    gen_server:enter_loop(?MODULE, [], #state{conn       = Conn1,                                              connname   = ConnName,                                              peername   = PeerName,                                              peerhost   = PeerHost,                                              peerport   = PeerPort}).

完整的源码下载地址:http://download.csdn.net/download/libaineu2004/10113319

阅读全文
0 0
原创粉丝点击