Erlang gen_tcp: семантика recv(Socket, Length)

Прочитав этот ответ, я хочу понять, относится ли то же самое к звонкам gen_tcp:recv(Socket, Length), Мое понимание документации заключается в том, что если это больше, чем Length байты доступны в буфере, они остаются там; если есть меньше чем Length байт, вызов блокируется до тех пор, пока не будет доступно достаточно или соединение не будет закрыто.

В частности, это должно работать, когда к пакетам добавляется 2 байта с префиксом в порядке с прямым порядком байтов:

receive_packet(Socket) ->
  {ok, <<Length:16/integer-little>>} = gen_tcp:recv(Socket, 2),
  gen_tcp:recv(Socket, Length).

Это правильно?

1 ответ

Да (или Нет, см. Комментарии для деталей).

Рассматривать:

Оболочка 1:

1> {ok, L} = gen_tcp:listen(8080, [binary, {packet, 0}, {active, false}]).
{ok,#Port<0.506>}
2> {ok, C} = gen_tcp:accept(L). %% Blocks
...

Оболочка 2:

1> {ok, S} = gen_tcp:connect("localhost", 8080, [binary, {packet, 0}]).
{ok,#Port<0.516>}
2> gen_tcp:send(S, <<0,2,72,105>>).
ok
3>

Оболочка 1 продолжение:

...
{ok,#Port<0.512>}
3> {ok, <<Len:16/integer>>} = gen_tcp:recv(C, 2).
{ok,<<0,2>>}
4> Len.
2
5> {ok, Data} = gen_tcp:recv(C, Len).
{ok,<<"Hi">>}
6>

Однако это полезно, если вы хотите только подтвердить поведение. На самом деле вы бы изменили {packet, N} опция, определяющая, сколько байтов должно быть длиной пакета (в системах с прямым порядком байтов).

То же, что и раньше, но без извлечения длины явно (обратите внимание, длина пакета = 2 в оболочке 1):

Оболочка 1:

1> {ok, L} = gen_tcp:listen(8080, [binary, {packet, 2}, {active, false}]).
{ok,#Port<0.506>}
2> {ok, C} = gen_tcp:accept(L). %% Blocks
...

В этом случае Эрланг удалит первые 2 байта и recv/2 будет блокировать, пока столько байтов, сколько ему нужно. В этом случае длина чтения должна быть 0 в recv/2,

Оболочка 2:

1> {ok, S} = gen_tcp:connect("localhost", 8080, [binary, {packet, 0}]).
{ok,#Port<0.516>}
2> gen_tcp:send(S, <<0,2,72,105>>).
ok
3>

Оболочка 1:

...
{ok,#Port<0.512>}
3> {ok, Data} = gen_tcp:recv(C, 0).
{ok,<<"Hi">>}

В этом случае я не указываю {packet, N} вариант в оболочке 2, просто чтобы показать идею, но обычно это не 0. Если packet опция установлена ​​тогда gen_tcp автоматически добавит / уберет столько байтов из пакета.

Если вы указываете пакет 0, то вы должны сделать recv/2 с длиной>= 0, и поведение такое же, как в C. Вы можете смоделировать неблокирующие приемы, дав короткий тайм-аут при выполнении приема, и в этом случае будет возвращено {error, timeout}.

Подробнее об этом можно прочитать здесь: http://www.erlang.org/doc/man/gen_tcp.html http://www.erlang.org/doc/man/inet.html#setopts-2

Надеюсь, это прояснит ситуацию.

Другие вопросы по тегам