The last few days I have been playing with gen_tcp and writing a simple TCP server. I have found a number of resources helpful:
gen_tcp,
miniserv,
20bits and
Programming Erlang. My server will run and display the data sent to it along with the client IP address and a timestamp. The server will also echo back whatever the client sent. It uses {active, once} for flow control as well. I just used telnet as my client. Pretty simple but a good exercise to see how this stuff works.
erl_tcp.erl
-module(erl_tcp).
-export([start_server/0, connect/1, recv_loop/1]).
-define(LISTEN_PORT, 9000).
-define(TCP_OPTS, [binary, {packet, raw}, {nodelay, true}, {reuseaddr, true}, {active, once}]).
start_server() ->
% start up the service and error out if we cannot
case gen_tcp:listen(?LISTEN_PORT, ?TCP_OPTS) of
{ok, Listen} -> spawn(?MODULE, connect, [Listen]),
io:format("~p Server Started.~n", [erlang:localtime()]);
Error ->
io:format("Error: ~p~n", [Error])
end.
connect(Listen) ->
{ok, Socket} = gen_tcp:accept(Listen),
inet:setopts(Socket, ?TCP_OPTS),
% kick off another process to handle connections concurrently
spawn(fun() -> connect(Listen) end),
recv_loop(Socket),
gen_tcp:close(Socket).
recv_loop(Socket) ->
% reset the socket for flow control
inet:setopts(Socket, [{active, once}]),
receive
% do something with the data you receive
{tcp, Socket, Data} ->
io:format("~p ~p ~p~n", [inet:peername(Socket), erlang:localtime(), Data]),
gen_tcp:send(Socket, "I Received " ++ Data),
recv_loop(Socket);
% exit loop if the client disconnects
{tcp_closed, Socket} ->
io:format("~p Client Disconnected.~n", [erlang:localtime()])
end.
Hopefully all of that made some sense. Here is an example of usage, first starting the server and receiving a message.
[zeusfaber@der-dieb ebin]$ erl
Erlang (BEAM) emulator version 5.6.5 [source] [64-bit] [smp:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.6.5 (abort with ^G)
1> erl_tcp:start_server().
To send the message "TEST123" I simply used telnet. Of course you could also write a client in Erlang to do the same.
[zeusfaber@der-dieb ~]$ telnet localhost 9000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
TEST123
I Received TEST123