如何使用 gen_tcp 检测 Elixir 中活动套接字上的 TCP 超时?
How can I detect a TCP timeout on an active socket in Elixir with gen_tcp?
我有一个 GenServer
正在通过 gen_tcp
连接到远程 TCP 连接。
opts = [:binary, active: true, packet: :line]
{:ok, socket} = :gen_tcp.connect('remote-url', 8000, opts}
我正在处理消息:
def handle_info({:tcp, socket, msg}, stage) do
IO.inspect msg
{:noreply, state}
end
效果很好。但是,TCP 服务器容易超时。如果我使用 gen_tcp.recv
,我可以指定超时。但是,我正在使用 active: true
来接收带有 handle_info
的消息,而不必循环调用 recv
。因此,GenServer
愉快地等待下一条消息,即使服务器已超时。
当 GenServer
在 X 秒后还没有收到来自 TCP 连接的消息时,我如何才能触发一个函数?我卡在使用 recv
了吗?
如果 TCP 连接本身已经超时,那么您应该会收到一条已关闭的套接字消息 {tcp_closed, Socket}
。在 handle_info
中对此进行匹配,仅此而已。至于在连接上建立 你自己的 超时,我通常使用 erlang:send_after/3
给自己发送消息——有效地添加我可以在 [=12= 中接收的超时消息语义] 或可能存在的任何 receive
服务循环。
erlang:send_after(?IDLE_TIMEOUT, self(), {tcp_timeout, Socket})
这必须与每次收到流量时取消计时器配对。这可能看起来像:
handle_info({tcp, Socket, Bin}, State = #s{timer = T, socket = Socket}) ->
_ = erlang:cancel_timer(T),
{Messages, NewState} = interpret(Bin, State),
ok = handle(Messages),
NewT = erlang:send_after(?IDLE_TIMEOUT, self(), {tcp_timeout, Socket})
{noreply, NewState#s{timer = NewT}};
handle_info({tcp_closed, Socket}, State = #s{timer = T, socket = Socket}) ->
_ = erlang:cancel_timer(T),
NewState = handle_close(State),
{noreply, NewState};
handle_info({tcp_timeout, Socket}, State = #s{socket = Socket}) ->
NewState = handle_timeout(State),
{noreply, NewState};
handle_info(Unexpected, State) ->
ok = log(warning, "Received unexpected message: ~tp", [Unexpected]),
{noreply, State}.
我有一个 GenServer
正在通过 gen_tcp
连接到远程 TCP 连接。
opts = [:binary, active: true, packet: :line]
{:ok, socket} = :gen_tcp.connect('remote-url', 8000, opts}
我正在处理消息:
def handle_info({:tcp, socket, msg}, stage) do
IO.inspect msg
{:noreply, state}
end
效果很好。但是,TCP 服务器容易超时。如果我使用 gen_tcp.recv
,我可以指定超时。但是,我正在使用 active: true
来接收带有 handle_info
的消息,而不必循环调用 recv
。因此,GenServer
愉快地等待下一条消息,即使服务器已超时。
当 GenServer
在 X 秒后还没有收到来自 TCP 连接的消息时,我如何才能触发一个函数?我卡在使用 recv
了吗?
如果 TCP 连接本身已经超时,那么您应该会收到一条已关闭的套接字消息 {tcp_closed, Socket}
。在 handle_info
中对此进行匹配,仅此而已。至于在连接上建立 你自己的 超时,我通常使用 erlang:send_after/3
给自己发送消息——有效地添加我可以在 [=12= 中接收的超时消息语义] 或可能存在的任何 receive
服务循环。
erlang:send_after(?IDLE_TIMEOUT, self(), {tcp_timeout, Socket})
这必须与每次收到流量时取消计时器配对。这可能看起来像:
handle_info({tcp, Socket, Bin}, State = #s{timer = T, socket = Socket}) ->
_ = erlang:cancel_timer(T),
{Messages, NewState} = interpret(Bin, State),
ok = handle(Messages),
NewT = erlang:send_after(?IDLE_TIMEOUT, self(), {tcp_timeout, Socket})
{noreply, NewState#s{timer = NewT}};
handle_info({tcp_closed, Socket}, State = #s{timer = T, socket = Socket}) ->
_ = erlang:cancel_timer(T),
NewState = handle_close(State),
{noreply, NewState};
handle_info({tcp_timeout, Socket}, State = #s{socket = Socket}) ->
NewState = handle_timeout(State),
{noreply, NewState};
handle_info(Unexpected, State) ->
ok = log(warning, "Received unexpected message: ~tp", [Unexpected]),
{noreply, State}.