Using OTP
Pupeno
pupeno@REDACTED
Sat Jan 14 17:44:09 CET 2006
Hello,
I've been trying for days to start working in a project of mine in Erlang not
being able to see how it should be coded according to OTP.
I've read the OTP Designs and principles, but that didn't really told me all I
needed.
What I am doing is a library to make servers[1], it is supposed to make
abstractions over protocols like DNS, SMTP, POP3, etc leaving you only to
worry about data handling.
I'll show you what I want with a trivial example: the echo protocol[2].
Someone wants to write a echo server, so it would write this:
-module(echo).
-export([start/0, init/1, echo/1]).
-behaviour(gen_echo).
start() ->
gen_echo:start(?MODULE, [], []).
init(_Args) ->
{10007, 10007}.
echo(Data) ->
string:concat("You said: ", Data).
where start/0 would start the server, init/1 replies with the TCP and UDP
ports to use (false or something like that in any of them would mean "don't
use that transport, tcp or udp").
The function echo/1 is the real worker here. In the DNS example (one in which
I worked on HaServers[1]), it would be query/1 and it would get a big record
containing the data sent by the client. echo/1 replies another string which
will be sent to the ip client (either by tcp, or udp, the good thing is that
echo/1 doesn't worry about that). As you can see, this is a non-compliant
echo server where the smart developer is doing some experimentation. In the
DNS example, query/1 would return a record containing the a packet to be sent
back.
Another callback function possible for DNS would be transfer/N, which is
triggered for transferring actions. Other protocols (smtp, pop3, imap4, which
are my priorities after dns, in that order) would have other set of
callbacks.
Now, my gen_echo.erl looks like this:
-module(gen_echo).
-export([behaviour_info/1]).
-export([start/3]).
-export([tcpLoop/2, tcpHandler/1]).
behaviour_info(callbacks) ->
[{echo, 1}];
behaviour_info(_Args) ->
undefined.
start(Mod, Args, Options) ->
{TCPPort, _UDPPort} = Mod:init(Args),
{_, TCPLSocket} = gen_tcp:listen(TCPPort, [{active, once}, {packet, 0}]),
spawn(?MODULE, tcpLoop, [Mod, TCPLSocket]).
tcpLoop(Mod, TCPLSocket) ->
{_, Socket} = gen_tcp:accept(TCPLSocket),
TcpHandler = spawn(?MODULE, tcpHandler, [Mod]),
gen_tcp:controlling_process(Socket, TcpHandler),
tcpLoop(Mod, TCPLSocket).
tcpHandler(Mod) ->
receive
{tcp, Socket, Data} ->
gen_tcp:send(Socket, Mod:echo(Data)),
inet:setopts(Socket, [{active, once}]),
tcpHandler(Mod);
{tcp_closed, Socket} ->
io:format("~w closed.~n", [Socket]);
Unknown ->
io:format("Received unknow message ~w.~n", [Unknown])
end.
I want to rewrite this as Erlangish and OTPish as possible, what do you
recommend ? what should I do ? Some questions I have are:
- Should gen_echo, gen_PROTOCOL, be a gen_server ? or another gen_X ?
- Should gen_echo, gen_PROTOCOL, use gen (gen:start, etc, I see that
gen_server uses it) ?
- Should I write supervisors ?
- Should all this be an application (ErServers, the temporary name for this
will only be a library, it shouldn't provide any runable program except a
couple of examples, any developed server should be packaged and developed
separately) ?
Any other tips and hints are welcome, I feel very lost here.
--
Pupeno <pupeno@REDACTED> (http://pupeno.com)
Vendemos: Kit del guitarrista: http://pupeno.com/vendo/#kit
[1] For those of you that understand Haskell, I started working on Haskell and
the result was HaServers http://software.pupeno.com/HaServers/
[2] RFC862.
PS: All this will be free software.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20060114/6c0e228a/attachment.bin>
More information about the erlang-questions
mailing list