Erlang ssl неблокирующие параллельные акцепторы - PullRequest
2 голосов
/ 09 марта 2012

Я построил очень наивный параллельный ssl-акцептор.

-module(multiserver).
-export([start/0,client/1]).

%% This is a dummy SSL Erlang server/client example

start() ->
    spawn_link(fun() -> init([]) end).

init([]) ->
    ssl:start(),
    {ok, ListenSocket} = ssl:listen(9990, [{certfile, "cert.pem"}, {keyfile, "privkey.pem"} ,{reuseaddr, true},{active, true}, binary]),
    Pid = self(),
    spawn_link(fun() -> listener(ListenSocket, Pid, 1) end),
    spawn_link(fun() -> listener(ListenSocket, Pid, 2) end),

    loop().

loop() ->
    receive 
        {new, _Pid} ->
            %% Do stuff here
            loop()
    end.

listener(ListenSocket, Pid, Num) ->
    {ok, ClientSocket} = ssl:transport_accept(ListenSocket),
    ok = ssl:ssl_accept(ClientSocket),
    io:format("listener ~p accepted ~n", [Num]),

    ok = ssl:send(ClientSocket, "server"),
    io:format("listener ~p  sent~n", [Num]),

    receive
        X -> io:format("listener ~p: ~p ~n", [Num, X])
    after 5000 ->
            io:format("listener ~p timeout ~n", [Num]),
            timeout
    end,
    ssl:close(ClientSocket),

    listener(ListenSocket, Pid, Num).

client(Message) ->
    ssl:start(),
    {ok, Socket} = ssl:connect("localhost", 9990,  [binary, {active,true}], infinity),

    receive
        X -> io:format("~p ~n", [X])
    after 2000 ->
            timeout
    end,
    ok = ssl:send(Socket,  Message),    

    ssl:close(Socket),
    io:format("client closed~n").

Проблема, с которой я столкнулся, заключается в том, что слушатель 2 не может получать никаких сообщений. Пример прогона программы выглядит так:

Сначала я запускаю сервер в оболочке 1. Оболочка 1:

1> multiserver:start().
<0.34.0>

Затем я трижды звоню клиенту / 1 из другой оболочки. Оболочка 2:

2> multiserver:client("client").
{ssl,{sslsocket,new_ssl,<0.51.0>},<<"server">>} 
client closed
ok
3> multiserver:client("client").
{ssl,{sslsocket,new_ssl,<0.54.0>},<<"server">>} 
client closed
ok
4> multiserver:client("client").
{ssl,{sslsocket,new_ssl,<0.56.0>},<<"server">>} 
client closed
ok

Это распечатки на серверную оболочку. Оболочка 1:

listener 1 accepted 
listener 1  sent
listener 1: {ssl,{sslsocket,new_ssl,<0.51.0>},<<"client">>} 
listener 2 accepted 
listener 2  sent
listener 1 accepted 
listener 1  sent
listener 1: {ssl,{sslsocket,new_ssl,<0.54.0>},<<"client">>} 
listener 2 timedout 
2> 

Я провел несколько часов с этим, и я не могу понять, почему для слушателя 2 невозможно получить какие-либо данные. Если я редактирую код для использования gen_tcp, он работает как положено. Есть ли что-то, что мне не хватает? Возможно ли это сделать с текущим модулем ssl?

1 Ответ

2 голосов
/ 09 мая 2012

Причина тайм-аута заключается в том, что во втором процессе используется опция сокета {active, false} , то есть receive никогда не получит никакого сообщения.

В документах erlang для модуля ssl указано, что сокет, созданный путем вызова transport_accept / 1, должен наследовать параметры, установленные для сокета слушателя.Первый процесс наследует параметры, когда выполняет transport_accept / 3, но по какой-то причине второй процесс этого не делает.Вы можете проверить параметры с помощью

ssl:getopts(ClientSocket,[mode, active])

Я понятия не имею, почему это происходит, но обходной путь заключается в том, чтобы явно установить параметры во вновь принятом сокете

ssl:setopts(ClientSocket, [{active,true}, {mode,binary}])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...