Erlang gen_tcp:recv(Socket,Length)语义 [英] Erlang gen_tcp:recv(Socket, Length) semantics

查看:231
本文介绍了Erlang gen_tcp:recv(Socket,Length)语义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

阅读此答案后,我想了解一下是否适用于对 gen_tcp:recv(Socket,Length)的调用。我对文档的理解是,如果超过长度字节在缓冲区中可用,则它们将保留在该位置;如果少于长度字节,则调用块直到足够可用或连接关闭。

After reading this answer, I want to understand if the same applies to the calls to gen_tcp:recv(Socket, Length). My understanding of the documentation is that this if more than Length bytes are available in the buffer, they remain there; if there is less than Length bytes, the call blocks until enough is available or connection closes.

当数据包以2位字节为前缀时,应以小端序为单位保存数据包长度:

In particular, this should work when packets are prefixed by 2 bytes holding packet length in little-endian order:

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

这是正确的吗?

推荐答案

是(否否,详情请见评论)

Yes (or No, see comments for details).

考虑:

Shell 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
...

Shell 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>

Shell 1 cont:

Shell 1 cont:

...
{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} 选项来定义应该是数据包长度的字节数(在big-endian系统上)。

However this is useful if you only want to confirm the behaviour. In reality you would change the {packet, N} option to define how many bytes that should be the packet length (on big-endian systems).

与之前相同但没有明确提取长度(在shell 1中注意包长度= 2):

Same as before but without extracting length explicitly (note packet length = 2 in shell 1):

Shell 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
...

在这种情况下,Erlang将剥离前2个字节, recv / 2 将阻塞,直到需要多少字节。在这种情况下, recv / 2 中的<长> 必须为0。

In this case Erlang will strip the first 2 bytes and recv/2 will block until as many bytes it needs. In this case read-length must be 0 in recv/2.

Shell 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>

Shell 1:

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

我没有在shell 2中指定 {packet,N} 选项,只是为了显示想法,但通常不是0.如果 选项设置然后 gen_tcp 将自动附加/删除包中的许多字节。

In this case I don't specify the {packet, N} option in shell 2 just to show the idea but normally it is not 0. If the packet option is set then gen_tcp will automatically append/strip that many bytes from the package.

如果指定数据包0,则必须执行长度> = 0的 recv / 2 ,并且行为与C中的行为相同。您可以模拟非阻塞在这种情况下通过短时间收到,并在这种情况下返回{error,timeout}。

If you specify packet 0 then you must do a recv/2 with a length >= 0 and the behaviour is the same as in C. You can simulate non-blocking receives by giving a short time out when doing the receive and this will return {error, timeout} in that case.

更多信息可以在这里阅读:
http://www.erlang.org/doc/man/gen_tcp.html
http://www.erlang.org/doc/man/inet.html#setopts-2

More on that can be read here: http://www.erlang.org/doc/man/gen_tcp.html http://www.erlang.org/doc/man/inet.html#setopts-2

希望这样可以清除。

这篇关于Erlang gen_tcp:recv(Socket,Length)语义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆