erlang socket (using ranch) close in a short time? - sockets

i use ranch to listen socket, but in a short time about five seconds, ranch closed the socket, and my setting of socket is above, so what' wrong?
{ok, _} = ranch:start_listener(server,200, ranch_tcp, [{port, 5555},{active, once}, {max_connections, 1024}], server_protocol, []), %% start the listener
the protocol file is below, the ranch listen to accept a socket, and the reverse the receive data, but what's wrong is that, when send data back to the client, after about five seconds, the client receive the message says that the socket is closed by server, i don't know if is ranch's default settings cause this?
-module(reverse_protocol).
-behaviour(gen_server).
-behaviour(ranch_protocol).
%% API.
-export([start_link/4]).
%% gen_server.
-export([init/1]).
-export([init/4]).
-export([handle_call/3]).
-export([handle_cast/2]).
-export([handle_info/2]).
-export([terminate/2]).
-export([code_change/3]).
-define(TIMEOUT, 5000).
-record(state, {socket, transport}).
%% API.
start_link(Ref, Socket, Transport, Opts) ->
proc_lib:start_link(?MODULE, init, [Ref, Socket, Transport, Opts]).
%% gen_server.
%% This function is never called. We only define it so that
%% we can use the -behaviour(gen_server) attribute.
init([]) -> {ok, undefined}.
init(Ref, Socket, Transport, _Opts = []) ->
ok = proc_lib:init_ack({ok, self()}),
ok = ranch:accept_ack(Ref),
ok = Transport:setopts(Socket, [{active, once}]),
gen_server:enter_loop(?MODULE, [],
#state{socket=Socket, transport=Transport},
?TIMEOUT).
handle_info({tcp, Socket, Data}, State=#state{
socket=Socket, transport=Transport}) ->
Transport:setopts(Socket, [{active, once}]),
Transport:send(Socket, reverse_binary(Data)),
{noreply, State, ?TIMEOUT};
handle_info({tcp_closed, _Socket}, State) ->
{stop, normal, State};
handle_info({tcp_error, _, Reason}, State) ->
{stop, Reason, State};
handle_info(timeout, State) ->
{stop, normal, State};
handle_info(_Info, State) ->
{stop, normal, State}.
handle_call(_Request, _From, State) ->
{reply, ok, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%% Internal.
reverse_binary(B) when is_binary(B) ->
[list_to_binary(lists:reverse(binary_to_list(
binary:part(B, {0, byte_size(B)-2})
))), "\r\n"].

So your problem is because your gen_server process is timing out and shutting down. The socket being closed is a side effect of this because ranch links the Socket to the spawned handler process.
Once the new process enters the gen_server loop with the call to gen_server:enter_loop, it has ?TIMEOUT milliseconds to receive a message before it is sent a timeout message.
-define(TIMEOUT, 5000).
init(Ref, Socket, Transport, _Opts = []) ->
ok = proc_lib:init_ack({ok, self()}),
ok = ranch:accept_ack(Ref),
ok = Transport:setopts(Socket, [{active, once}]),
gen_server:enter_loop(?MODULE, [],
#state{socket=Socket, transport=Transport},
?TIMEOUT). %% timeout because of this!
handle_info({tcp, Socket, Data}, State=#state{
socket=Socket, transport=Transport}) ->
Transport:setopts(Socket, [{active, once}]),
Transport:send(Socket, reverse_binary(Data)),
{noreply, State, ?TIMEOUT}; %% timeout because of this!
So when those five second pass and the gen_server hasn't received any messages in that time it sends itself a timeout message, which is then handled by handle_info
handle_info(timeout, State) ->
{stop, normal, State};
Your handle_info tells the gen_server to stop, which causes the Socket to close because the two are linked together.
You can either remove the timeouts completely, or just stop the timeout from causing the process to close.
Here is how I would change the handle_info timeout code:
handle_info(timeout, State) ->
io:format("the socket is idle~n"),
{noreply,State};

Related

erlang udp server can't receive accept packets

I have one simple udp server written in gen_server behaviour. When I run it, and try to send message by using gen_udp:send, the server replies nothing, seems like the udp server didn't accept packet successfully. Here is my code
gen_udp_server.erl:
-module(gen_udp_server).
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-export([start_link/1]).
-define(SERVER, ?MODULE).
-record(state, {socket,
port,
local_ip,
broad_ip}).
start_link(Port) ->
{ok, Socket} = gen_udp:open(Port, [binary,
{active, false},
{reuseaddr, true}]),
gen_server:start_link(?MODULE, [Socket, Port], []).
init([Socket, Port]) ->
{ok, #state{socket = Socket, port = Port}}.
handle_cast(_Request, State) ->
{noreply, State}.
handle_call(_Request, _From, State) ->
{noreply, State}.
handle_info({udp, _Socket, _Addr, _Port, Data}, #state{socket = Socket} = State) ->
inet:setopts(Socket, [{active, once}]),
io:format("Server received data ~p from socket ~p~n", [Data, Socket]),
{ok, State}.
terminate(_Reason, {socket = LSocket}) ->
gen_udp:close(LSocket).
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
Starting server on server 192.168.146.129: gen_udp_server:start_link(10000).
Sending message from 192.168.146.128:
{ok, Socket} = gen_udp:open(4399, [binary, {active, false}]).
gen_udp:send(Socket, {192,168,146,129}, 10000, "hello").
The udp server should print some message when it receives packets, but my one failed. Can anyone help me?
handle_info() deals with unknown messages (i.e. unhandled messages) that arrive in the gen_server's mailbox. But when a process opens a socket in passive mode: {active, false}, messages sent to the socket do not land in the process's mailbox. Instead, the process has to manually read messages from the socket by calling gen_udp:recv(Socket, Length). After all, the whole point of creating a passive socket is to keep messages from flooding the process's mailbox. As a result, handle_info() doesn't get called when a client sends a message to a passive socket.
Furthermore, because gen_server is event driven you need to call gen_udp:recv(Socket, Length) in response to some event. For instance, you could define the server functions:
process_message() ->
gen_server:cast(?MODULE, process_msg).
handle_cast(process_msg, #state{socket=Socket} = State) ->
Data = gen_udp:recv(Socket, 0),
io:format("Server received data ~p from socket ~p~n", [Data, Socket]),
{noreply, State}.
Then you need someone to periodically call process_message(). The following seems to work:
start() ->
io:format("start~n"),
{ok, Server} = gen_server:start_link({local,?MODULE}, ?MODULE, [], []),
Poller = spawn(?MODULE, poll, []), %%<***** HERE *****
io:format("Server: ~w~nPoller: ~w~n", [Server,Poller]).
...
...
handle_cast(process_msg, #state{socket=Socket} = State) ->
case gen_udp:recv(Socket, 10000, 500) of
{error, timeout} -> %%Timeout message.
ok;
{error, Error} ->
io:format("Error: ~p~n", [Error]);
Data ->
io:format("Server received data ~p from socket ~p~n", [Data, Socket])
end,
{noreply, State}.
poll() ->
timer:sleep(1000),
process_message(),
poll().
As for the Length in the recv(), I'm not sure what you're supposed to specify: I tried 0, 2, and 10,000, and I couldn't discern a difference.
Here's my client:
client() ->
Port = 15000,
{ok, Socket} = gen_udp:open(0, [binary, {active, false}]),
gen_udp:send(Socket, "localhost", Port, "hello").
Note that open(0, ....) instructs erlang to open any free port (the client and the server cannot open the same port if running on the same computer--contrary to what you need with a gen_tcp socket). However, gen_udp:send() must specify the same port that the server opened. Also, the atom localhost and the list "localhost" both work for me.
Complete server code:
-module(s2).
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-export([start/0, process_message/0, poll/0]).
-record(state, {socket,
port,
local_ip,
broad_ip}).
%%======== PASSIVE SOCKET: {active,false} ===========
%% External interface:
start() ->
io:format("start~n"),
{ok, Server} = gen_server:start_link({local,?MODULE}, ?MODULE, [], []),
Poller = spawn(?MODULE, poll, []),
io:format("Server: ~w~nPoller: ~w~n", [Server,Poller]).
process_message() ->
gen_server:cast(?MODULE, process_msg).
poll() ->
timer:sleep(1000),
process_message(),
poll().
%%Internal server methods:
init([]) ->
Port = 15000,
{ok, Socket} = gen_udp:open(Port, [binary,
{active, false},
{reuseaddr, true}]),
{ok, #state{socket = Socket, port = Port}}.
handle_cast(process_msg, #state{socket=Socket} = State) ->
case gen_udp:recv(Socket, 10000, 500) of
{error, timeout} -> %%Timeout message.
ok;
{error, Error} ->
io:format("Error: ~p~n", [Error]);
Data ->
io:format("Server received data ~p from socket ~p~n", [Data, Socket])
end,
{noreply, State}.
handle_call(_Request, _From, State) ->
{noreply, State}.
handle_info(Msg, State) ->
io:format("Msg: ~w, State:~w~n", [Msg, State]),
{noreply, State}.
terminate(_Reason, #state{socket = LSocket}) ->
gen_udp:close(LSocket).
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
In the shell:
shell #1---
$ erl
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.2 (abort with ^G)
1> c(s2).
{ok,s2}
2> s2:start().
start
Server: <0.64.0>
Poller: <0.65.0>
ok
shell #2--
$ erl
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.2 (abort with ^G)
1> c(c2).
{ok,c2}
2> c2:client().
ok
shell #1--
Server received data {ok,{{127,0,0,1},61841,<<"hello">>}} from socket #Port<0.2110>
3>
shell #2--
3> c2:client().
ok
4>
shell #1--
Server received data {ok,{{127,0,0,1},63983,<<"hello">>}} from socket #Port<0.2110>
3>

how to use gen_sctp:send/3

I am making an example when using gen_sctp create soscket and associates in server-client model.
In server side:
{ok,serverSocket} = gen_sctp:open(1234,[{ip,{127,0,0,1}},{reuseaddr,true},{active,true}]).
ok = gen_sctp:listen(S,true).
In client side:
{ok,Client} = gen_sctp:open(1243,[{ip,{127,0,0,1}},{reuseaddr,true}]).
{ok,Ass} = gen_sctp:connect(S,{127,0,0,1},1234,[{active,true}]).
And then client send message to server by send/4:
gen_sctp:send(S,Ass,2,<<"hellooooo">>).
And message receive in server side:
{sctp,#Port<0.6126>,
{127,0,0,1},
1243,
{[{sctp_sndrcvinfo,2,1,[],0,0,0,1409953138,0,18}],
<<"hellooooo">>}}
So how can server can reply message to client by send/3?
Thanks and Best Regards,
Tran.
gen_sctp:send/3 is like gen_sctp:send/4 but you can set more flags and options. You have already used gen_sctp:send/4 in client code (while you messed around with client and server sockets):
{ok, Assoc} = gen_sctp:connect(ClientSocket, {127,0,0,1}, 1234,[{active,true}]).
gen_sctp:send(ClientSocket, Assoc, 2, <<"hellooooo">>).
And Assoc is of sctp_assoc_change record type while gen_sctp:send/4 looks just for assoc_id if you provide sctp_assoc_change. So currently providing #sctp_assoc_change{} or just association id behave exactly same.
And how one can find out association id of client in server? It's provided in message which server received:
{sctp,#Port<0.6126>,
{127,0,0,1},
1243,
{[{sctp_sndrcvinfo,2,1,[],0,0,0,1409953138,0,18}],
<<"hellooooo">>}}
#sctp_sdnrcvinfo{} record has fields telling association id and stream number which data is received from. You can get current association id from assoc_id field and pass it to another gen_sctp:send/4:
gen_sctp:send(ServerSocket, AssocID, 2, <<"welcome!">>).
Stream number of 2 probably won't make it fail because by default gen_sctp:open makes 10 incoming and outgoing streams, but you can safely provide 0 as stream number.
Here is an example of sending and receiving data with sctp:
#!/usr/bin/escript
-include_lib("kernel/include/inet_sctp.hrl").
server_loop(Socket) ->
receive
{sctp, Socket, _FromIP, _FromPort, {[#sctp_sndrcvinfo{assoc_id=AssocID}],
Payload}} ->
gen_sctp:send(Socket, #sctp_sndrcvinfo{assoc_id=AssocID, stream=0},
<<"pong">>),
% or less complex gen_sctp:send/4
gen_sctp:send(Socket, AssocID, 0, <<"pong">>);
Rest ->
io:format("server got unhandled message ~w~n", [Rest])
end,
server_loop(Socket).
create_server_socket() ->
{ok, Socket} = gen_sctp:open(1234, [{ip,{127,0,0,1}}, {reuseaddr,true},
{active,true}]),
gen_sctp:listen(Socket, true),
{ok, Socket}.
run_server() ->
Spawner = self(),
spawn_link(fun() ->
{ok, Socket} = create_server_socket(), Spawner ! ready, server_loop(Socket)
end),
receive
ready ->
io:format("server is up~n"),
ok
after 100 ->
throw(server_timeout)
end.
ping_server() ->
{ok, Socket} = gen_sctp:open(1243, [{ip,{127,0,0,1}}, {reuseaddr, true}]),
{ok, AssocChange} = gen_sctp:connect(Socket, {127,0,0,1}, 1234, [{active, true}]),
gen_sctp:send(Socket, AssocChange, 2, <<"ping">>),
receive
{sctp, Socket, _FromIP, _FromPort, {[#sctp_sndrcvinfo{}], Payload}} ->
io:format("client got payload ~p~n", [Payload])
after 2000 ->
throw(client_timeout)
end.
main([]) ->
run_server(),
ping_server().

gen_tcp:accept Error Listen Socket Is Closed?

Writing a very simple TCP server for starters, but for the life of me, gen_tcp:accept in my 'accept_loop' function keeps returning {error, closed} immediately when it's called. So far I've been able to get everything else working thus far, but this one is really stumped me. Wondering if I fell into a beginner trap.
Anyway here is the code.
-module(doom_server).
-behaviour(gen_server).
-export([start_link/1, handle_client/1, accept_loop/1, accept/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-define(TCP_OPTIONS, ).
-record(server_state, {
port,
ip=any,
timeout=10,
lsocket=null}).
start_link(_Args) ->
gen_server:start_link(?MODULE, _Args, []).
init(_Args) ->
% Get configuration from doom.config and create a new server state.
Port = proplists:get_value(port, _Args),
BindAddress = proplists:get_value(bind_address, _Args),
Timeout = proplists:get_value(timeout, _Args),
case gen_tcp:listen(Port, [binary,
{packet, 0},
{active, false},
{reuseaddr, true}]) of
{ok, ListenSocket} ->
% Construct our server state.
NewState = #server_state {
lsocket = ListenSocket,
port = Port,
ip=BindAddress,
timeout=Timeout
},
{ok, accept(NewState)};
{error, Reason} ->
io:format("Failed: ~w~n", [Reason]),
{stop, Reason}
end.
handle_cast({accepted, _Pid}, State=#server_state{}) ->
{noreply, accept(State)}.
accept_loop({Server, ListenSocket, Timeout}) ->
case gen_tcp:accept(ListenSocket, Timeout) of
{ok, Socket} ->
% Let the server spawn a new process and replace this loop
gen_server:cast(Server, {accepted, self()}),
handle_client(Socket);
{error, Type} ->
io:format("Error: ~w~n", [Type])
end.
% To be more robust we should be using spawn_link and trapping exits
accept(State = #server_state{lsocket=ListenSocket, timeout=Timeout}) ->
proc_lib:spawn(?MODULE, accept_loop, [{self(), ListenSocket, Timeout}]),
State.
handle_client(Socket)->
case gen_tcp:recv(Socket, 0) of
{ok, Data} ->
gen_tcp:send(Socket, Data),
handle_client(Socket);
{error, closed} ->
ok
end.
% We get compile warnings from gen_server unless we define these
handle_call(_Msg, _Caller, State) -> {noreply, State}.
handle_info(_Message, Library) -> {noreply, Library}.
terminate(_Reason, _Library) -> ok.
code_change(_OldVersion, Library, _Extra) -> {ok, Library}.
I've ran erlang:port_info(ListenSocket) just after the gen_tcp:listen and inside the accept_loop. Both output the same data, and if I put gen_tcp:accept inside the main thread or right after the gen_tcp:listen it works as expected. Am I doing something wrong when I spawn a new process?
P.S I'm using this tutorial as point of reference: http://20bits.com/article/erlang-a-generalized-tcp-server

Why code version controller does not work in erlang?

I Wrote this module for a simple server program that receives a request and send a response to client. It works fine But when if recompile this module while a client connected, the client disconnects and if i reconnect client to this server and send a request, there is no response. Is there any idea?!
Here is my module:
-module(controller).
-export([start/1, loop/1, response/2]).
-include_lib("types.hrl").
-define(END_CHAR, "$").
-spec start(Port) -> no_return() when
Port :: char().
-spec loop(Listen) -> no_return() when
Listen :: port().
-spec handler(Socket) -> no_return() when
Socket :: port().
-spec response(HandlerPID, Data) -> {send_msg, Msg} when
HandlerPID :: pid(),
Data :: string(),
Msg :: response().
start(Port) ->
{ok, Listen} = gen_tcp:listen(Port, [{active, once}]),
spawn(?MODULE, loop, [Listen]).
loop(Listen) ->
{ok, Socket} = gen_tcp:accept(Listen),
spawn(?MODULE, loop, [Listen]),
handler(Socket).
handler(Socket) ->
receive
{tcp, Socket, Data} ->
%io:format("recv ~p~n", [Data]),
spawn(?MODULE, response, [self(), Data]),
inet:setopts(Socket, [{active, once}]),
handler(Socket);
{tcp_closed, Socket} ->
%io:format("disconnected~n", []),
gen_tcp:close(Socket);
{send_msg, Msg} ->
gen_tcp:send(Socket, lists:flatten(io_lib:format("~p", [Msg])) ++ ?END_CHAR),
handler(Socket)
end.
response(PID, Data) ->
[Req|Args] = string:tokens(Data, ?END_CHAR),
{ReqPID, ReqRef} = spawn_monitor(view, request, [list_to_atom(Req), self(), Args]),
receive
{'DOWN', ReqRef, process, ReqPID, {function_clause, _}} -> PID ! {send_msg, invalid_request};
{'DOWN', ReqRef, process, ReqPID, {{case_clause, _}, _}} -> PID ! {send_msg, bad_args};
{'DOWN', ReqRef, process, ReqPID, {{badmatch, _}, _}} -> PID ! {send_msg, bad_args};
Resp -> PID ! {send_msg, Resp}
end.
Note
{tcp_closed, Socket} ->
%io:format("disconnected~n", []),
gen_tcp:close(Socket);
in handler. It doesn't call handler again, it just returns and so the server process stops.
Your loop function name is also misleading, handler is the actual loop.
I would recommend to take a look at Ranch - A socket acceptor pool for the TCP connections.

Erlang process gets stuck

Im working on erlang for the first time. everytime i try to run the erlang process it gets stuck and does not take input. Im using erlide plugin in eclipse to test the erlang code.
CODE IS::
-module(message_router).
%% ====================================================================
%% API functions
%% ====================================================================
%%-compile(export_all).
-export([start/0]).
-export([stop/1]).
-export([send_chat_message/3]).
-export([route_messages/0]).
%% ====================================================================
%% Internal functions
%% ====================================================================
start() ->
spawn(message_router, route_messages, []).
stop(RouterPid) ->
RouterPid ! shutdown.
send_chat_message(RouterPid, Addressee, MessageBody) ->
io:format("send_chat_msg FROM:: ~p TO:: ~p ~n", [RouterPid, Addressee]),
RouterPid ! {send_chat_msg, Addressee, MessageBody}.
route_messages() ->
receive
{send_chat_msg, Addressee, MessageBody} ->
io:format("recv_chat_msg PID:: ~p ~n", [Addressee]),
Addressee ! {recv_chat_msg, MessageBody},
route_messages();
{recv_chat_msg, MessageBody} ->
io:format("Received: ~p~n", [MessageBody]);
shutdown ->
io:format("Shutting down ~n");
Oops ->
io:format("Warning! Received: ~p~n", [Oops]),
route_messages()
end.
When i hit try to run the code like in the shell
Eshell V5.10.4
(nodename#pa)1> P1 = message_router:start().
<0.1308.0>
(nodename#pa)2> P2 = message_router:start().
<0.1373.0>
(nodename#pa)3> chat_client:send_message(P1, P2, "FIRST Msg").
Sending chat message from chat_client
send_chat_msg FROM:: <0.1308.0> TO:: <0.1373.0>
Every thing i enter in the shell after this has on effect. Also could anyone explain how loops are handled in erlang and best practices.
[edit]
chat client code:
-module(chat_client).
-export([send_message/3]).
send_message(RouterPid, Addressee, MessageBody) ->
io:format("Sending chat message from chat_client~n"),
message_router:send_chat_message(RouterPid, Addressee, MessageBody).
Problem in module. Call this message_router:send_chat_message(P1, P2, "FIRST Msg")
Look at this example and compare with his:
Have module call observer it registers two process loop/0 and trans/0
-module(observer).
-export([observer/0, loop/0, trans/0]).
observer() ->
register(loop, spawn(fun observer:loop/0)),
register(trans, spawn(fun observer:trans/0)).
loop() ->
receive
{'PRINT', Msg} ->
io:format("print from ~p~n~p~n", [self(), Msg]), loop();
{'EXIT', _FromPid} ->
io:format("Exit ~nFrom ~p", [_FromPid]), exit(self(), kill)
end.
trans() ->
receive
{Command, Msg} -> io:format("transports from: ~p~n~p~n", [self(), Msg]),
loop ! {Command, Msg}
end.
and have module send_messenger one function send_message that sends messages through trans:
-module(send_messenger).
-export([send_message/1]).
send_message({Command, Msg}) ->
trans ! {Command, Msg},
ok.
I hope this has helped you!