我编写简单的http客户端,遇到以下问题,我从官方文档中复制do_recv
,但它的工作方式很奇怪:
do_recv(Sock, Bs) ->
case gen_tcp:recv(Sock, 0, ?TIMEOUT) of
{ok, B} ->
gen_tcp:shutdown(Sock, write), % <-- this appears to fix the problem!
do_recv(Sock, [Bs, B]);
{error, closed} ->
{ok, list_to_binary(Bs)}
end.
聊天顺序如下:
{ok, S} = gen_tcp:connect(Ip, Port, [inet, binary,
{packet, 0},
{active, false},
{nodelay, true},
{reuseaddr, true}], 2000),
Req = io_lib:format("GET ~s HTTP/1.1\r\nHost: ~s\r\n\r\n", [Url, UrlHost]),
ok = gen_tcp:send(S, list_to_binary(Req)) of
do_recv(S, []);
对do_recv
的最终调用有时会按预期工作并返回服务器
respose,但有时它挂起和超时,我想因为服务器没有关闭套接字
在其自己的。
所以第二个超时的情况是我想避免的,任何想法
如何应对这种行为?
UPD:
我添加了gen_tcp:shutdown
调用do_recv
函数(请参阅代码示例中的注释),
这似乎解决了这个问题。问题是我知道的非常noobish和解决方案
非常像猜测,也许还有人可以解释这里发生的事情
他们通常如何解决这类问题。
答案 0 :(得分:3)
您的代码存在一些问题。
如果你收到0,你可以获得GET字符串的一半,或者你可以获得超过整个GET字符串,具体取决于内核处理流的方式。 TCP是面向流的,所以你需要从套接字中获取数据,直到你有足够的数据。此外,您可以轻松地以{error,timeout}触发结束,因此您也必须处理该问题。否则它将无法按预期工作。基本上你需要一个收集数据的循环,直到你有足够的数据来解析GET。在获得所有数据之前,超时将在该循环中发生。
有些事情:
do_recv(Sock, Gathered) ->
case gen_tcp:recv(Sock, 0, ?TIMEOUT) of
{ok, Bin} ->
Remaining = try_decode(Sock, <<Gathered/binary, Bin/binary>>),
do_recv(Sock, Remaining);
{error, timeout} ->
do_recv(Sock, Remaining);
{error, Reason} ->
exit(Reason)
end.
try_decode(Sock, Gathered) ->
case decode(Gathered) of
{ok, Data, Rest} ->
processor ! Data,
try_decode(Sock, Rest);
need_more_data ->
do_recv(Sock, Gathered)
end.
这里假设了几件事