2017-04-26 21 views
0

私はソケットクライアントアプリケーションを持っています。アプリケーション起動時にソケットが作成され(サーバーとの接続が確立され)、並列に実行される2つのスレッドが開始されます。マルチスレッドソケット通信のシナリオ

スレッド1:(データが受信されるまでブロック)を連続的読み出し方法を使用してソケットを読み出し

スレッド2:連続データを書き込みます。

スレッド2がIO例外を受け取った場合、既存のソケットを破棄して新しいソケットを作成し、通信を開始します。スレッド2はソケットを破棄するため、スレッド1はヌルポインタ例外を受け取ります。 これを処理する戦略はありますか

+0

これは「非同期」ではありません。これはマルチスレッドです。同じことではありません。 – EJP

答えて

0

proactorシステムデザインのスタイルに関連する問題が発生し始めています。この問題を解決するには、2つのスレッド間の通信が必要です。このコミュニケーションが何であるかを選ぶことは、それが乱雑になるところです。 thread1がソケットを読み込もうとするのを止める何かでなければなりません。私はJavaではそれほど良くはありませんが、Cではシグナルを使うことを意味します。

Javaで同等のものがあっても、信号を避けることをお勧めします。

より良い選択肢は、select()(またはJava同等のもの)の呼び出しでthread1をブロックし、ソケットとパイプで待機することです。 Thread2はソケットを閉じるときにパイプに書き込み、thread1はselect()から戻り、thread2への応答をパイプに書き込んだり、select()をパイプでのみ呼び出す。 Thread2はその応答を読み取り、ソケットを閉じ、新しいソケットを開き、パイプの下に何か別のものを送ってthread1を再び起動させます。今度はselect()に戻ることができますが、今回はパイプと新しいソケットで戻ります。これにより、thread1とthread2の間でランデブ実行が達成されます。 thread1がソケットを使用していないときに(パイプ通信を介して)知っているので、thread2は古いソケットを閉じて新しいソケットを開くことができます。

これはやや乱雑です。さらに、reactorのデザインパターンのようになっています。どちらの場合でも、実行中のループの一部としてソケットを読み取るかどうかを選択するために、select()を使用するスレッドを1つだけ持つこともできます。この単一スレッドは、利用可能なときにデータを読み取ることになり、データが到着することを期待してブロッキング読み取りを実行しません。ソケットの書き込みに何か問題が生じ、ソケットを交換する必要がある場合は、単純にそうします。他に同期するスレッドはありません。ソケットがネットワーク上のリモートサーバーに接続されていると仮定すると(同じマシン上のサービスではなく)、イーサネットの速度は支配的なボトルネックになります。原子炉スタイルのシステムはそれほど遅くはありません。

reactorシステムスタイルでは、ネットワーク障害を扱うのがはるかに簡単です。なぜなら、他のスレッドが不適切であると判断したアクションを実行するためのスレッドがないからです。残念ながら、ほとんどのプログラミング環境はproactorです(Windows、Boost ASIO、RabbitMQなど)。何か問題が起こるまでは、Proactorシステムは問題ありません。その後、プログラマーにとっては非常に複雑になる可能性があるため、ボーク処理されたコールバックと非同期IOをすべて整理します。

可能な場合は、ZeroMQを使用することもできます。 ZeroMQをどこでも使用する必要がありますが(サーバも)、ネットワークの問題に対処するのがはるかに簡単です。これはリアクターであり、プロクターではありません。

1

スレッド2は、ソケットを閉じる前にソケットをシャットダウンする必要があります。これにより、スレッドはストリームを受信して​​終了し、ソケットを閉じて終了する必要があります。次に、スレッド2は別のソケットを作成し、別の読み取りスレッドを開始することができます。

関連する問題