Почему spawn/3 (MFA) не работает в Erlang?

Вот простой сервер на Erlang. Я пытаюсь создать с помощью spawn/3, но мне приходится прибегать к использованию spawn/1, чтобы заставить его работать.

-module(server_by_name).
-export([start/0]).

start() ->
    {ok, Listen} = gen_tcp:listen(1234, [binary, {packet, 0}, {reuseaddr, true}, {active, true}]),
    io:format("Server running."),
    % --> Why doesn't this work in place of the line below? --> spawn(server_by_name, connect, [Listen]).
    spawn(fun() -> connect(Listen) end).

connect(Listen) ->
    {ok, Socket} = gen_tcp:accept(Listen),
    spawn(fun() -> connect(Listen) end),
    io:format("Connection accepted on ~p Pid ~p~n", [Socket, self()]),
    receive
        {tcp, Socket, Bin} ->
            Request = parse_request(Bin),
            io:format("File requested: ~p~n", [Request]),
            LoadHtml = file:read_file(Request),
            case LoadHtml of
                {ok, Reply} ->
                    Header = "HTTP/1.1 200 OK \r\n Content-Type:HTML\r\n\r\n",
                    ConnectCheck = gen_tcp:send(Socket, Header ++ Reply),
                    io:format("Connection?? ~p~n", [ConnectCheck]);
                {error, Reason} ->
                    io:format("Error in loading html file: ~n~p~n", [Reason]);
            end;
        {tcp_closed, Socket} ->
            io:format("Server socket closed~n")
    after 5000 ->
        io:format("Client unresponsive~n")
    end.

parse_request(Bin) when is_binary(Bin)->
    parse_request(binary_to_list(Bin));

parse_request("GET /" ++ RestStr) ->
    get_request([], RestStr);

parse_request([_H|T]) ->
    parse_request(T).

get_request(Request, [32|_RestStr]) ->
    lists:reverse(Request);

get_request(Request, [H|RestStr]) ->
    get_request([H|Request], RestStr);

get_request(Request, []) ->
    io:format("Unexpected result in server_by_name:get_request()"),
    list:reverse(Request).

Я включил весь код, чтобы вы могли скопировать/вставить его и попробовать сами, если это необходимо. Вам просто нужно иметь файл, который можно обслуживать в том же каталоге, и запросить его по имени. Очевидно, что в нем нет мер предосторожности и т. д.


person GenericJam    schedule 15.03.2013    source источник


Ответы (1)


spawn/3 требует, чтобы функция была экспортирована. Ваше решение вполне разумно, но вы также можете экспортировать connect/1:

-export([connect/1]).  %% do not use, exported for spawn
person legoscia    schedule 15.03.2013
comment
Я просто новичок в Erlang, но, насколько я понимаю, для горячей замены кода вам нужно использовать spawn/3 или spawn/4. Есть ли способ горячей замены кода, не делая приватные функции общедоступными? - person GenericJam; 15.03.2013
comment
Нет, нет. Процесс будет использовать новую версию модуля, если и когда вы сделаете вызов внешней функции, используя либо spawn/3, либо spawn/4, либо вызов my_module:function(something) (в отличие от function(something)) в вашем коде. - person legoscia; 15.03.2013