I\'m starting to learn Erlang, so I\'m trying to write the \"hello, world!\" of concurrent programming, an IRC bot.
I\'ve already written one using Erlang without any O
Another way to implement an asynchronous TCP listener is by using supervisor_bridge.
Here is some code that I wrote to show this (not tested):
-module(connection_bridge).
-behaviour(supervisor_bridge).
% supervisor_bridge export
-export([init/1, terminate/2]).
% internal proc_lib:start_link
-export([accept_init/3]).
%% Port: see gen_tcp:listen(Port, _).
%% Options: see gen_tcp:listen(_, Options).
%% ConnectionHandler: Module:Function(Arguments)->pid() or fun/0->pid()
%% ConnectionHandler: return pid that will receive TCP messages
init({Port, Options, ConnectionHandler}) ->
case gen_tcp:listen(Port, Options) of
{ok, ListenSocket} ->
{ok, ServerPid} = proc_lib:start_link(?MODULE, accept_init,
[self(), ListenSocket, ConnectionHandler], 1000),
{ok, ServerPid, ListenSocket};
OtherResult -> OtherResult
end.
terminate(_Reason, ListenSocket) ->
gen_tcp:close(ListenSocket).
accept_init(ParentPid, ListenSocket, ConnectionHandler) ->
proc_lib:init_ack(ParentPid, {ok, self()}),
accept_loop(ListenSocket, ConnectionHandler).
accept_loop(ListenSocket, ConnectionHandler) ->
case gen_tcp:accept(ListenSocket) of
{ok, ClientSocket} ->
Pid = case ConnectionHandler of
{Module, Function, Arguments} ->
apply(Module, Function, Arguments);
Function when is_function(Function, 0) ->
Function()
end,
ok = gen_tcp:controlling_process(ClientSocket, Pid),
accept_loop(ListenSocket, ConnectionHandler);
{error, closed} ->
error({shutdown, tcp_closed});
{error, Reason} ->
error(Reason)
end.
A lot easier to understand than my other answer. The connection_bridge
can be extended to support UDP and SCTP too.