[英]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.