November 12, 2008

A Simple Concurrent Erlang TCP Server.

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().
{{2008,11,12},{11,20,28}} Server Started.
ok
{ok,{{127,0,0,1},48940}} {{2008,11,12},{11,20,35}} <<"TEST123\r\n">>
2>

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

2 Comments

  1. leesort Dec 18, 2008 12:52 am

    very helpful to me. thanks.

  2. joe Dec 18, 2008 5:32 pm

    cool, glad it helped.

Leave a Comment

(required)

(will not be published) (required)