use*_*425 1 erlang elixir gen-tcp
我有一个GenServer通过连接到远程TCP连接的gen_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会向自己发送一条消息-有效地添加可以在handle_info任何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}.
Run Code Online (Sandbox Code Playgroud)