2016-12-05 8 views
0

私は一般的にactive-modeでは、単一のTCPリソースと対話するため、このパターンを使用します。1 GenServerからアクティブモードで複数のTCP接続の管理

def connect(ip, port) do 
    t = System.system_time(1000) 
    case :gen_tcp.connect(ip, port, [:binary, active: :once, keepalive: true, nodelay: true]) do 
     {:ok, socket} -> 
     log "Connected to #{ip}:#{port} in #{System.system_time(1000) - t}ms" 
     socket 
     {:error, err} -> 
     log "Connect Error - #{ip}: #{port} [#{inspect err}]" 
     Process.send_after(self(), :retry_connect, 3000) 
     nil 
    end 
    end 

    def handle_info({:tcp, _, data}, s) do 
    s = proc_raw(s.extra <> data, %{s | extra: ""}) 

    :inet.setopts(s.socket, active: :once) 

    {:noreply, s} 
    end 
これは中 複数 TCP接続を処理するために拡張することができますどのように

同じGenServer

は、これまでのところ、これはactive-mode

更新

各GenServerが監督の下で管理されている中で、単一のTCPソケットのために素晴らしい作品。また、各GenServerは1つのクライアントを表し、各クライアントはいくつかの外部リソースに対して3〜5のTCP接続を持つことがあります。 TCPコネクションの

失敗/リセットは再接続がそれぞれの障害に試され、随時予想されますが、ホストGenServerは、私はあなたがGenServerではなくSupervisorを使用することをお勧めしたい

+0

接続ごとに1つのプロセスが必要なのはなぜですか?個々の接続が終了する可能性があり、他の接続に影響を与えるべきではないため、接続を分離することは理にかなっています。 –

+0

各GenServerは単一のクライアントインスタンス用です。各クライアントインスタンスは、同じTCPリソースへの最大5つのtcp接続を管理します。 –

+0

@MartinSvalinクローズまたは失敗したTCP接続が管理され再開されます。プロセスが予期された動作であるためクラッシュしません。 –

答えて

2

私は@Onorio Catenacciに同意しますが、複数のGenServersがおそらくより良い方法です。しかし、私は依頼した質問にはまだ答えます。

handle_infoに渡されたタプルの2番目の位置が、データを受信して​​いるソケットです。したがって、あなたはすでにどのソケットから来ているのか知っています。

handle_info({:tcp, socket, data}, s) do 
    # do something with the socket here ... 
end 

私は必要なだけで、他の変更はのようなものであることをコネクト機能や、あなたのGenServerのinit機能のためhandle_callを変更することによって行うことができ、開いているすべてのソケットへの参照を保持している疑いがあるでしょう:

def init(_) do 
    {:ok, []} 
end 

def handle_call({:connect, ip, port}, _from, sockets) do 
    s = connect(ip, port) 
    {:reply, :ok, [s|sockets]} 
end 

同様に、handle_callも:retry_connect関数を変更する必要があります。

これが役に立ちます。

+0

ありがとう、私はソケットが 'handle_info({:tcp、socket、data}、s) –

+0

スタンドアロンモードの場合、私は現在接続ごとに1つのGenServerという名前を使用しています。私は複数のGenServersを実行し、各Genserverに少数のTCP接続を管理させたいと考えています。 Onorio-Catenacciが私のシナリオでは理想的ではないと思われるもの –

2

を再起動する必要はありません。上司は、あなたが自動的に他のものの間で障害が発生し、接続を再起動することができます:

物事が失敗した場合、あなたの最初の反応は次のようになります。「のは、それらの エラーを救出しましょう」。しかし、Elixirでは、他の言語でよく見られるように、防御プログラミング習慣 の救済措置を避けています。代わりに、私たちは "let it crash"と言う。 クラッシュにレジストリを導くバグがある場合は、 スーパーバイザーを設定してレジストリの新しいコピーを開始するため、心配する必要はありません。

私は上記のパスが "レジストリ"について議論していることを認識していますが、コンセプトは同じです。

私の答えはやや一般的であることもわかります。しかし、あなたの質問もかなり一般的なので、より具体的なものを私に与えるのは難しいです。より具体的な質問がある場合は、質問を編集することをお勧めします。より具体的な回答を提供することができます。

+0

各GenServerは管理されています –

+0

だから、各GenServerが監督されている場合は、なぜ各GenServerで複数の接続を処理したいのですか?より多くのGenServersを起動してください。つまり、存在しない問題を解決しようとしているように見えるため、GenServersを追加する際にいくつかの制約がある場合は、それを質問に追加する必要があります。 –

+0

私はいくつかの文脈で質問を更新し、GenServerと接続の関係を与えてくれました –

関連する問題