3

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ため、サーバーがタイムアウトした場合でも、次のメッセージを喜んで待ちます。

GenServerX 秒後に TCP 接続からメッセージを受信して​​いない場合、関数をトリガーするにはどうすればよいですか? 私は使用して立ち往生していrecvますか?

4

1 に答える 1

7

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}.
于 2016-07-21T03:58:09.220 に答える