简体   繁体   English

Erlang gen_tcp:recv(Socket,Length)语义

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

After reading this answer , I want to understand if the same applies to the calls to gen_tcp:recv(Socket, Length) . 阅读此答案后 ,我想了解是否对gen_tcp:recv(Socket, Length)的调用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; 我对文档的理解是,如果缓冲区中有超过Length个字节可用,它们将保留在那里; if there is less than Length bytes, the call blocks until enough is available or connection closes. 如果少于“ Length字节,则调用将阻塞,直到有足够的可用空间或连接关闭为止。

In particular, this should work when packets are prefixed by 2 bytes holding packet length in little-endian order: 特别是,当数据包以2个字节为前缀并按小字节序保留数据包长度时,此方法应该起作用:

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

Is this correct? 这个对吗?

Yes (or No, see comments for details). 是(或否,请参阅评论以获取详细信息)。

Consider: 考虑:

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

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

Shell 1 cont: Shell 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>

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). 实际上,您将更改{packet, N}选项以定义应该为数据包长度的字节数(在big-endian系统上)。

Same as before but without extracting length explicitly (note packet length = 2 in shell 1): 与之前相同,但未明确提取长度(请注意,外壳1中的数据包长度= 2):

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

In this case Erlang will strip the first 2 bytes and recv/2 will block until as many bytes it needs. 在这种情况下,Erlang将剥离前2个字节,而recv/2将阻塞,直到需要多少字节为止。 In this case read-length must be 0 in recv/2 . 在这种情况下, recv/2读取长度必须为0。

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

Shell 1: 外壳1:

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

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. 在这种情况下,我并没有在shell 2中指定{packet, N}选项,只是为了展示这个主意,但通常它不是0。如果设置了packet选项,那么gen_tcp将自动从包中追加/剥离那么多字节。

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. 如果指定数据包0,则必须执行长度大于等于0的recv/2 ,并且其行为与C中相同。可以通过在接收时给出短暂的超时来模拟非阻塞接收,这将返回在这种情况下,{错误,超时}。

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 有关更多信息, 参见: http : //www.erlang.org/doc/man/gen_tcp.html http://www.erlang.org/doc/man/inet.html#setopts-2

Hope this clears things up. 希望这可以清除一切。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM