Non-blocking TCP server using OTP principles

前端 未结 3 1353
名媛妹妹
名媛妹妹 2021-02-06 05:39

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

3条回答
  •  谎友^
    谎友^ (楼主)
    2021-02-06 06:09

    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.

提交回复
热议问题