Erlang gen_tcp:recv(Socket,Length)语义 [英] Erlang gen_tcp:recv(Socket, Length) semantics
问题描述
阅读此答案后,我想了解一下是否适用于对 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屋!