2016-07-21 24 views
1

我有一個GenServer通過gen_tcp連接到遠程TCP連接。如何使用gen_tcp在Elixir的活動套接字上檢測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

+0

不知道爲什麼有人低估了這一點。這是許多人很早就用Erlang,Elixir,LFE等人使用'{active,true}'套接字所面臨的一個基本難題 - 而且這個解決方案不僅適用於Elixir。 – zxq9

回答

4

如果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}. 
+0

感謝您的回答!我也意識到,Elixir'GenServer's支持返回'timeout'值,所以{:noreply,state,timeout}'導致發送超時消息,如果在timeout內沒有收到其他消息。我不確定Erlang是否存在於gen_servers中,或者Elixir是否將它添加進去,但是這爲我解決了問題。如果我無法訪問該超時助手,您的解決方案也可以工作。謝謝! – user2666425

+0

@ user2666425是的,Erlang gen_servers具有完全相同的超時值,您可以將其包含在來自'handle_ *'調用的返回值中。 *但是*對於all_中的任何消息,這是一個超時_,並且這與TCP消息_的超時_不同。例如,如果你使用Erlang系統消息給你的TCP處理程序發送垃圾郵件,它將不斷重置該超時值並且錯過了套接字沒有活動的事實。這就是爲什麼這個特殊的用途,我添加自己的'tcp_timeout'消息作爲特定於套接字流量的消息。 – zxq9

+0

這很有道理。非常感謝您提供清晰有用的答案! – user2666425