Packages
diint_utilites_common_app
1.4.17
1.4.23
1.4.22
1.4.21
1.4.20
1.4.19
1.4.18
1.4.17
1.4.16
1.4.15
1.4.14
1.4.12
1.4.11
1.4.10
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.9
1.3.8
1.3.7
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.101
1.2.11
1.2.10
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.13
1.0.12
1.0.11
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
библиотеки для работы с ребитом и протоколы
Current section
Files
Jump to
Current section
Files
src/network/socket_client.erl
%%%-------------------------------------------------------------------
%%% @author cheese
%%% @copyright (C) 2016, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 19. Feb 2016 15:24
%%%-------------------------------------------------------------------
-module(socket_client).
-author("cheese").
-behaviour(gen_server).
-include("../../include/types_network.hrl").
-include_lib("kernel/include/logger.hrl").
-define(TIMEOUT_CONNECT, 5000).
-define(TIMEOUT_START, 3000).
-define(REGISTER_CHECK, 7000).
-record(state, {
socket_info :: #socket_info{},
socket_instance
}).
%% API
-export([start_link/1, send_message/2, handle_message/2, handle_one_message/2, execute_handle_messages/2]).
%% gen_server
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
%% API
-spec(start_link(#socket_info{}) -> 'ignore' | {'error',_} | {'ok',pid()}).
start_link(Socket) ->
Name = Socket#socket_info.name,
?LOG_INFO("start_link: ~w~n", [?MODULE]),
?LOG_INFO("ConsumerSocket ~w: ~p~n", [Name, Socket]),
consumer_control:unregister(#consumer_info{name = Name}),
gen_server:start_link({local, Name}, ?MODULE, [Socket], []).
send_message(Bytes, ServerName) ->
gen_server:call(ServerName, {send, Bytes}).
%%%===================================================================
-spec(init([#socket_info{}]) -> {ok,#state{}}).
init([Socket]) ->
Name = Socket#socket_info.name,
?LOG_INFO("init: ~w, ~p~n", [?MODULE, Socket]),
gen_server:cast(Name, {init, Socket}),
{ok, #state{}}.
%%%===================================================================
handle_call({send, Bytes}, _From, State) ->
Res = case gen_tcp:send(State#state.socket_instance, Bytes) of
ok ->
?LOG_INFO("Send [ok] to ~w ~w bytes: ~s~n", [State#state.socket_info#socket_info.name, erlang:byte_size(Bytes), bytes_extension:bin_to_hexstr(Bytes)]),
ok;
{error, Reason} ->
?LOG_INFO("Send [error: ~w] to ~w ~w bytes: ~s~n", [Reason, State#state.socket_info#socket_info.name, erlang:byte_size(Bytes), bytes_extension:bin_to_hexstr(Bytes)]),
{error, Reason}
end,
{reply, Res, State};
handle_call(_Request, _From, State) ->
{reply, ok, State}.
%%===================================================================
handle_cast({init, SocketInfo}, State) ->
Name = SocketInfo#socket_info.name,
Ip = SocketInfo#socket_info.ip,
Port = SocketInfo#socket_info.port,
?LOG_INFO("Try connect to ~p:~w~n", [Ip, Port]),
Socket = case gen_tcp:connect(Ip, Port, [binary, {packet, 0}, {keepalive, true}], ?TIMEOUT_CONNECT) of
{ok, SocketConnected} ->
erlang:send_after(?REGISTER_CHECK, self(), {register, Name}),
consumer_control:register(#consumer_info{name = Name, pid = self()}),
SocketConnected;
{error, Reason} ->
?LOG_INFO("Connect failed: ~w~n", [Reason]),
socket_utilites:timeout_seconds(1000),
error(Reason)
end,
?LOG_INFO("Connected to ~p:~w success: ~w ~n", [Ip, Port, Socket]),
NewState = State#state{
socket_info = SocketInfo,
socket_instance = Socket
},
{noreply, NewState};
%%===================================================================
handle_cast(_Request, State) ->
{noreply, State}.
%%%===================================================================
handle_info({tcp, RemoteSocket, Bytes}, State) ->
Name = State#state.socket_info#socket_info.name,
{ok,{Ip,Port}} = inet:peername(RemoteSocket),
?LOG_INFO("Receive message from ~w [~p:~w] ~w bytes: ~s~n", [Name, Ip,Port, erlang:byte_size(Bytes), bytes_extension:bin_to_hexstr(Bytes)]),
handle_message(Bytes, State),
{noreply, State};
%%%===================================================================
handle_info({tcp_closed, RemoteSocket}, State) ->
Name = State#state.socket_info#socket_info.name,
?LOG_INFO("Client disconnected: ~w~n", [RemoteSocket]),
consumer_control:unregister(#consumer_info{name = Name, pid = self()}),
error(disconnect),
{noreply, State};
%%%===================================================================
handle_info({register, Name}, State) ->
consumer_control:register(#consumer_info{name = Name, pid = self()}),
{noreply, State};
%%%===================================================================
handle_info(Info, State) ->
?LOG_INFO("Unknown message in socket: ~w~n", [Info]),
{noreply, State}.
%%%===================================================================
terminate(_Reason, _State) ->
ok.
%%%===================================================================
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
get_file_name(Name) ->
"log/" ++ atom_to_list(Name) ++ ".log".
%%***************
%% ------------------------------------------------------------------
%% Если обработчик события есть - обрабатываем
%% ------------------------------------------------------------------
handle_message(Bytes, #state{ socket_info = #socket_info{} } = State ) ->
Messages = socket_utilites:prepare_l2l1_messages_from_bytes(binary:bin_to_list(Bytes), []),
execute_handle_messages(Messages, State).
%% ------------------------------------------------------------------
%% Запустить на обработку все сообщения
%% ------------------------------------------------------------------
execute_handle_messages(ignored, #state{ socket_info = #socket_info{ } } ) ->
?LOG_INFO("message ignored"),
ok;
execute_handle_messages([], _State) ->
ok;
execute_handle_messages([{HeadMessage} | OtherMessage], State) ->
spawn(?MODULE, handle_one_message, [HeadMessage, State]),
execute_handle_messages(OtherMessage, State).
%% ------------------------------------------------------------------
%% Запустить на обработку одно конкретное сообщение
%% ------------------------------------------------------------------
handle_one_message(Bytes, #state{ socket_info = #socket_info{ handler = Handler }}) ->
case Handler of
undefined -> {undefined, handler_is_absent};
_ -> try Handler(Bytes) of
Res -> Res
catch
ErrRes ->
?LOG_INFO("Consumer handler error: ~w~n", [ErrRes]),
ErrRes
end
end.