在 gen_tcp 文档中有如下说明:
The fact that the send call does not accept a timeout option, is because timeouts on send is handled through the socket option send_timeout. The behavior of a send operation with no receiver is in a very high degree defined by the underlying TCP stack, as well as the network infrastructure. If one wants to write code that handles a hanging receiver that might eventually cause the sender to hang on a send call, one writes code like the following.
大致意思为,sender 发送时没有 receiver 的情况,已经通过底层 TCP 协议栈很好的解决了,如果 sender 想使用带 timeout 功能的 send ,则需要在 connect 的时候指定 {send_timeout, xxx} 。
假定的使用场景(取自 gen_tcp ):
business process <--> client process(connect) <--> server process(accept)
...
gen_tcp:connect(HostAddress, Port, [{active,false}, {send_timeout, 5000}, {packet,2}]),
loop(Sock),
...
In the loop where requests are handled, we can now detect send timeouts:
loop(Sock) ->
receive
%% 这里是来自 business 的消息发送命令
{Client, send_data, Binary} ->
case gen_tcp:send(Sock,[Binary]) of
%% 这里完成针对 send 的超时处理
{error, timeout} ->
io:format("Send timeout, closing!~n", []),
%% 可以针对超时做业务处理
handle_send_timeout(), % Not implemented here
Client ! {self(),{error_sending, timeout}},
%% Usually, it's a good idea to give up in case of a
%% send timeout, as you never know how much actually
%% reached the server, maybe only a packet header?!
%% 这里建议直接关闭
gen_tcp:close(Sock);
{error, OtherSendError} ->
io:format("Some other error on socket (~p), closing",
[OtherSendError]),
Client ! {self(),{error_sending, OtherSendError}},
gen_tcp:close(Sock);
ok ->
Client ! {self(), data_sent},
loop(Sock)
end
end.
通常情况下,上述代码足以检测 receive 端的超时问题。大多数协议都会存在某种来自 server 端的确认机制,若存在,则不需要上述代码实现的 send 超时检测。需要使用的唯一场景是应用层协议是单向、无确认机制的情况。