erlang udp server can't receive accept packets - sockets

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>

Related

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

can't get data via gen_udp

i run tcpdump -i eth0 -vv ip6 on remote server and see such packets
11:10:36.712804 IP6 (hlim 1, next-header UDP (17) payload length: 103) fe80::f816:3eff:fe94:a348.57100 > ff3c::8500:2345.57100: [udp sum ok] UDP, length 95
but when i open Socket
{ok, Socket} = gen_udp:open(57100, [binary, {active, true}, {ip, any}, inet6, {reuseaddr, true}])
or
{ok, Socket} = gen_udp:open(57100, [binary, {active, true}, {ip, any}, inet6, {multicast_ttl, 225}, {multicast_loop, false}, {reuseaddr, true}])
or
{ok, Socket} = gen_udp:open(57100, [binary, {active, true}, {ip, {65340,0,0,0,0,0,34048,9029}}, inet6, {multicast_ttl, 225}, {multicast_loop, false}, {reuseaddr, true}])
{65340,0,0,0,0,0,34048,9029} = <<"FF3C:0000:0000:0000:0000:0000:8500:2345">>
and waiting for message in such way
subscribe_on_stream() ->
%% {ok, Socket} = gen_udp:open(57100, [binary, {active, true}, {ip, IP}, inet6, {multicast_ttl, 225},
%% {multicast_loop, false}, {reuseaddr, true}]),
{ok, Socket} = gen_udp:open(Port, [binary, {active, true}, {reuseaddr, true}]),
io:format("self: ~p line: ~p~n", [self(), ?LINE]),
subscribe_loop(Socket).
subscribe_loop(Socket) ->
receive
Any ->
io:format("~p~n", [Any])
end.
The problem is on the subscribe_loop(Socket). It's not actually looping. You call the function once, it returns and that's it. You need to call subscribe_loop(...) recursively to do a loop.
Here is an example of how to write a very simple server waiting for messages.
https://www.erlang.org/course/concurrent-programming
Solution:
subscribe_loop(Socket) ->
receive
Any ->
io:format("~p~n", [Any]),
subscribe_loop(Socket)
end.

tcp server accepting only some connections

I have a tcp server and a client. The client spawns 1000 processes each trying to connect to the tcp server. I can see that the tcp server is accepting 245 connections and rejecting all the rest. Every time, the server is accepting the first 245.
Fixes:
Tried to increase the backlog attribute but did not work.
Tried to call timer:sleep(N) after each process spawn so that I can reduce the rate at which tcp server can accept clients. Failed!
Server and client:
accept(LSocket) ->
case gen_tcp:accept(LSocket) of
{ok, Socket} ->
io:format("Accepted ~n"),
{sockets, List} = hd(ets:lookup(csockets, sockets)),
NewList = [Socket | List],
ets:insert(csockets, {sockets, NewList}),
Pid = spawn(fun() ->
loop(Socket, 0)
end),
gen_tcp:controlling_process(Socket, Pid),
accept(LSocket);
{error, closed} ->
error
end.
Client:
send(State = #state{low = Low, high = Low}) ->
NewState = receive_sockets(0, Low, State),
NewState;
send(State = #state{low = Low}) ->
N = Low rem 2,
Dest = lists:nth(2, State#state.dest),
loop(self(), Dest, Low),
NewState = State#state{low = Low + 1},
send(NewState).
loop(From, {IP, Port}, Low) ->
case gen_tcp:connect(IP, Port, []) of
{ok, Socket} ->
gen_tcp:send(Socket, integer_to_binary(Low)),
From ! {Low, Socket},
Pid = spawn(?MODULE, receive_from_other_users, []),
gen_tcp:controlling_process(Socket, Pid);
_Else ->
io:format("The connection failed ~n"),
loop(From, {IP, Port}, Low)
end.

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 socket (using ranch) close in a short time?

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};