Packages
diint_utilites_common_app
1.4.23
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_server.erl
-module(socket_server).
-behaviour(gen_server).
-include("../../include/types_network.hrl").
-include_lib("kernel/include/logger.hrl").
-record(state, {
socket_server_info :: #socket_info{},
socket_server_pid,
clients =[]}).
-define(TIMEOUT, 40000).
-export([send_to_last_accepted/2]).
-export([start_link/1, init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, stat/1]).
-export([internal_receive_from_client/3, internal_accept/4, internal_handle_raw_bytes/4, internal_execute_handle_on_messages/4, internal_handle_one_message/3, internal_is_valid_ip/2]).
%% ------------------------------------------------------------------
%% API Function Definitions
%% ------------------------------------------------------------------
-spec(start_link(#socket_info{}) -> {ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
start_link(#socket_info{name = Name} = SocketInfo) ->
?LOG_INFO("Start link server socket: ~w~n", [?MODULE] ),
gen_server:start_link({local, Name}, ?MODULE, [SocketInfo], []).
send_to_last_accepted(ServerName, Bytes) ->
gen_server:call(ServerName , {send_to_last_accepted, Bytes}).
stat(ServerName) ->
gen_server:call(ServerName, stat).
%% ------------------------------------------------------------------
%% gen_server Function Definitions
%% ------------------------------------------------------------------
-spec(init([#socket_info{}]) -> {ok, State :: #state{}}).
init([#socket_info{name = Name} = SocketInfo]) ->
?LOG_INFO("Init server socket: ~p~n", [SocketInfo] ),
gen_server:cast(Name, {init, SocketInfo}),
{ok, #state{}}.
%% ------------------------------------------------------------------
%% handle_call
%% ------------------------------------------------------------------
handle_call({send_to_last_accepted, Bytes}, _From, #state{ clients = Clients, socket_server_info = SocketInfo} = State) ->
Res = case Clients of
[] ->
?LOG_INFO("Clients is absent message ignored: ~p~n", [Bytes]),
{error, no_clients};
[Head | _] ->
ResSend = case gen_tcp:send(Head, Bytes) of
ok ->
?LOG_INFO("Send [ok] to ~w ~w bytes: ~s~n", [Head, 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, Head, erlang:byte_size(Bytes), bytes_extension:bin_to_hexstr(Bytes)]),
{error, Reason}
end,
ResSend
end,
{reply, Res, State};
%% ------------------------------------------------------------------
handle_call(stat, _From, State = #state{clients = Clients, socket_server_info = ServerInfo}) ->
{reply, {ok, ServerInfo, Clients}, State};
%% ------------------------------------------------------------------
handle_call(_Request, _From, State) ->
{reply, ok, State}.
%% ------------------------------------------------------------------
%% handle_cast
%% ------------------------------------------------------------------
handle_cast({init, SocketInfo}, _State) ->
#socket_info{port = Port, handler = Handler, name = Name, valid_ip = ValidIP} = SocketInfo,
socket_utilites:timeout_seconds(1000),
?LOG_INFO("Init socket: ~w, Server: ~w~n", [?MODULE, SocketInfo]),
case gen_tcp:listen(Port, [binary, {packet, 0},{active, false}, {reuseaddr, true}]) of
{ok, ServerSocketPid} ->
?LOG_INFO("Started server on port: ~p. ~p~n", [Port, ServerSocketPid]),
Pid = spawn_link(?MODULE, internal_accept, [ServerSocketPid, Handler, Name, ValidIP]),
?LOG_INFO("Accept Pid: ~p~n", [Pid]),
{noreply, #state{socket_server_info = SocketInfo, socket_server_pid = ServerSocketPid}};
{error, Reason} ->
?LOG_INFO("Error starting listen: ~p~n", [Reason]),
error(Reason)
end;
%% ------------------------------------------------------------------
handle_cast({remove_client, ClientPid}, #state{clients = Clients} = State) ->
NewClients = [S || S <- Clients, S /= ClientPid],
{noreply, State#state{clients = NewClients}};
%% ------------------------------------------------------------------
handle_cast({accept_socket_client, SocketClient}, #state{clients=Clients, socket_server_info = SocketInfo} = State) ->
NewClients=[SocketClient | Clients],
?LOG_INFO("Active clients [~w]: ~w~n", [length(NewClients), NewClients]),
NewState = State#state{
clients=NewClients
},
{noreply, NewState}.
%% ------------------------------------------------------------------
%% handle_info
%% ------------------------------------------------------------------
handle_info(test, State) ->
?LOG_INFO("State: ~p~n", [State]),
{noreply, State};
%% ------------------------------------------------------------------
handle_info(_Info, State) ->
?LOG_INFO("Handle_info: unknown"),
{noreply, State}.
%% ------------------------------------------------------------------
%% terminate
%% ------------------------------------------------------------------
terminate(_Reason, _State) ->
?LOG_INFO("Terminate: unknown"),
ok.
%% ------------------------------------------------------------------
%% code_change
%% ------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
?LOG_INFO("Code_change: unknown"),
{ok, State}.
%% ------------------------------------------------------------------
%% Пока сокет жив - ожидаем подключения
%% ------------------------------------------------------------------
internal_accept(ServerSocketPid, Handler, Name, ValidIP) ->
?LOG_INFO("Begin accept: ~p~n", [ServerSocketPid]),
Res = gen_tcp:accept(ServerSocketPid),
case Res of
{ok, SocketClientPid} ->
{ok,{Ip,Port}} = inet:peername(SocketClientPid),
case internal_is_valid_ip(Ip, ValidIP) of
true ->
?LOG_INFO("Accepted client ~p: ~w:~w~n", [SocketClientPid, Ip,Port]),
gen_server:cast(Name, {accept_socket_client, SocketClientPid}),
spawn(?MODULE, internal_receive_from_client, [SocketClientPid, Handler, Name]),
ok;
false ->
?LOG_INFO("Decline accept for client ~p: ~w:~w~n", [SocketClientPid, Ip,Port]),
gen_tcp:close(SocketClientPid),
ok
end,
internal_accept(ServerSocketPid, Handler, Name, ValidIP);
{error, Reason} ->
?LOG_INFO("Error accept: ~w~n",[{Reason}]),
error({error, Reason}),
{stopped, Reason}
end.
%% ------------------------------------------------------------------
internal_receive_from_client(SocketClientPid, Handler, Name) ->
?LOG_INFO("Start read from client ~w~n", [SocketClientPid]),
case gen_tcp:recv(SocketClientPid, 0) of
{ok, Bytes} ->
?LOG_INFO("Receive message from ~w ~w bytes: ~s~n", [SocketClientPid, erlang:byte_size(Bytes), bytes_extension:bin_to_hexstr(Bytes)]),
spawn(?MODULE, internal_handle_raw_bytes, [Handler, SocketClientPid, Bytes, Name]),
internal_receive_from_client(SocketClientPid, Handler, Name);
{error, closed} ->
gen_server:cast(Name, {remove_client, SocketClientPid}),
?LOG_INFO("Client disconnected: ~w~n",[{SocketClientPid}]),
{error, closed};
{error, Reason} ->
?LOG_INFO("Error receive: ~w~n",[{Reason}]),
{error, Reason};
Other ->
?LOG_INFO("Other receive tcp message: ~w~n",[Other]),
{error, Other}
end.
%% ------------------------------------------------------------------
%% Разбить на сообщения и выполнить
%% ------------------------------------------------------------------
internal_handle_raw_bytes(Handler, SocketClientPid, MessageBytes, Name) ->
Messages = socket_utilites:prepare_l2l1_messages_from_bytes(binary:bin_to_list(MessageBytes), []),
internal_execute_handle_on_messages(Handler, SocketClientPid, Messages, Name) .
%% ------------------------------------------------------------------
%% Запустить на обработку все сообщения
%% ------------------------------------------------------------------
internal_execute_handle_on_messages(_Handler, _SocketClientPid, [], _Name) ->
ok;
internal_execute_handle_on_messages(Handler, SocketClientPid, [{OneMessage} | OtherMessage], Name) ->
spawn(?MODULE, internal_handle_one_message, [Handler, OneMessage, SocketClientPid]),
internal_execute_handle_on_messages(Handler, SocketClientPid, OtherMessage, Name).
%% ------------------------------------------------------------------
%% Запустить на обработку одно конкретное сообщение
%% ------------------------------------------------------------------
internal_handle_one_message(Handler, Message, SocketClientPid) ->
Handler(Message, SocketClientPid).
internal_is_valid_ip(_, undefined) ->
true;
internal_is_valid_ip(_, []) ->
false;
internal_is_valid_ip(OneValidIP, [OneValidIP | _]) ->
true;
internal_is_valid_ip({N1, _N2, _N3, _N4}, [{N1, -1, -1, -1 } | _]) ->
true;
internal_is_valid_ip({N1, N2, _N3, _N4}, [{N1, N2, -1, -1 } | _]) ->
true;
internal_is_valid_ip({N1, N2, N3, _N4}, [{N1, N2, N3, -1 } | _]) ->
true;
internal_is_valid_ip(IP, [ _ | Tail]) ->
internal_is_valid_ip(IP, Tail).