Erlang. Параметры TCP/IP сокета

    Небольшая шпаргалка по параметрам TCP/IP сокетов в Erlang по-русски. Все взято от сюда:

    1) erlang.org/doc/man/gen_tcp.html
    2) www.erlang.org/doc/man/inet.html#setopts-2
    3) learnyousomeerlang.com/buckets-of-sockets#tcp-and-udp-brotocols

    Сразу пример:
    ...
    -define(TCP_OPTIONS, [binary, {packet, raw}, {active, false}]).
    ...
    {ok,Socket} = gen_tcp:listen(Port, ?TCP_OPTIONS),
    ...
    

    Параметры сокета задаются в массиве(листе) через запятую. Порядок и количество параметров определяется по вкусу.

    Режим, определяющий тип данных (mode)


    Выбирая режим, мы решаем, как VM Erlang будет давать нам информацию из сокета:
    binary — в виде двоичных данных;
    list — в виде списка
    Считается, что с двоичными данными Erlang работает быстрее, чем со списками.

    Пример
    Сокет принял данные из трех байт: 01 02 03
    %% в двоичном виде
    Msg = <<1,2,3>>, %% допустим, данные поместили в переменную Msg
    %% парсим
    <<FirstByte, Tail/binary>> = Msg,
    %% итог:
    %% в Msg будет 1
    %% в Tail будет <<2,3>>
    
    %% в виде списка(list)
    Msg = [1,2,3], %% данные
    %% парсим
    [FirstByte|Tail] = Msg, %% берем первый элемент и остаток сообщения
    %% итог:
    %% в Msg будет 1
    %% в Tail будет [2,3]
    


    Режим чтения данных из сокета (active)


    Этим параметром задается режим и способ чтения данных из сокета.

    В режиме {active, false} сокет работает в так называемом passive mode. Рекомендуется применять при больших объемах данных и высоких скоростях; в случаях, когда разная скорость работы сети у клиента и сервера; чтобы клиент не завалил сообщениями сервер. А все потому, что в этом режиме используется tcp/ip flow control (открытие для меня).

    Данные читаются непосредственно из сокета
    recv(Socket) ->
        case gen_tcp:recv(Socket, 0) of
            {ok, RcvdData} -> %% RcvdData - считанные данные
                recv(Sock);
            {error, closed} -> %% закрылся
                {error, closed}
        end.
    

    В режиме {active, true} данные, принятые из сокета отправляются процессу в виде сообщений. Но flow control тут нет, поэтому можно закидать принимающую сторону большим объемом данных.

    Данные из сокета передаются процессу в виде сообщений
    recv(Socket) ->
        receive
            {tcp, Socket, RcvdData} -> %% RcvdData - считанные данные
                recv(Sock);
            {tcp_closed, Socket} ->
                {error, closed}
        end.
    

    В принципе, в этом случае процесс тоже будет висеть на receive, пока не будут приняты сообщения. Но в этом случае можно обрабатывать сообщения с данными не только от сокета, но и от других процессов (например, сообщение с данными, которые нужно отправить в сокет).

    Параметры сокета можно менять на ходу
    inet:setopts(Socket, [{active, once}]),
    

    В режиме {active, once} сокет работает в активном режиме до приема первого сообщения. После этого он переходит в пассивный режим с управлением потоком (tcp flow control). Это как раз тот случай, когда мы хотим получать данные сокета в виде сообщений и в то же время нам нужен flow control. Каждый раз, когда мы хотим принимать данные, нам нужно менять свойство active у сокета.
    recv(Socket) ->
        inet:setopts(Socket, [{active, once}]),
        receive
            {tcp, Socket, RcvdData} -> %% RcvdData - считанные данные
                recv(Sock);
            {tcp_closed, Socket} ->
                {error, closed}
        end.
    


    Кроме once можно задать число. Подробнее можно прочесть в документации

    packet


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

    Данные из сокета могут приниматься как бессмысленным потоком, так и в виде определенных пакетов.

    В режиме {packet,0} или {packet,raw} данные никак не пакуются и передаются на обработку как есть.

    В режиме {packet,1 | 2 | 4} перед данными идет 1, 2 или 4 байта, которые задают длину сообщения. Сообщение попадет в процесс только после того, как будет принято полностью.

    В режиме {packet,line} данные будут собираться до получения символа перевода строки. Удобно, например, при написании сервера, который обрабатывает данные из терминала. Данные из сокета придут не отдельно по буквам, а уже в виде строки.

    Остальные варианты я не пробовал. С ними можно ознакомиться в [1] и [2].

    nodelay


    {nodelay, true|false} понятно без перевода. Значение типа boolean.

    buffer


    Размер буферов тоже можно поменять через {buffer, Size}. Причем val(buffer) >= max(val(sndbuf),val(recbuf)). Которые можно задать по отдельности.

    Про параметры сокетов достаточно.

    Хозяин сокета


    Процесс, который создал сокет, является его хозяином. Но сокет можно легко отдать другому процессу:
    gen_tcp:controlling_process(Socket, ProcessPID)
    


    Это все, что я хотел написать в tcp/ip Erlang шпаргалку.
    Поделиться публикацией

    Похожие публикации

    Комментарии 0

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

    Самое читаемое