1

同時に複数のクライアントと通信するサーバーをJavaで構築しています。最初のアプローチは、サーバーがクライアントからの接続をリッスンし、接続が受信されてソケットが作成されると、新しいスレッドが生成されることです各クライアントとの通信を処理します。つまり、ObjectInputStream を使用してリクエストを読み取り、目的の操作 (DB からデータをフェッチして更新するなど) を実行し、クライアントに応答を返します (必要な場合)。サーバー自体が戻って、より多くの接続をリッスンします。

これは当面は問題なく機能しますが、このアプローチは実際にはスケーラブルではありません。同時に接続されている少数のクライアントにはうまく機能しますが、すべてのクライアントが別のスレッドを生成するため、接続されているクライアントが多すぎるとどうなりますか一気に?

したがって、私の次のアイデアは、接続されているすべてのクライアント (ソケット オブジェクトといくつかの追加情報) を保持する並べ替えのリストを維持し、ThreadPool を使用してそれらを反復処理し、メッセージが受信された場合は送信されたものをすべて読み取ることでした。ワーカー スレッドの別の ThreadPool による実行のためのキュー。応答が必要な場合はワーカーがタスクを終了したら、それを送信します。

後の 2 つの手順は実装が非常に簡単です。問題は、クライアント実装ごとの元のスレッドで、ObjectInputStream.readObject() を使用してメッセージを読み取ることです。このメソッドは、読み取るものがあるまでブロックされますが、これは問題ありません。アプローチですが、すべてのソケットをブロックすると、リストのさらに下にあるソケットに到達することはないため、新しいアプローチに同じことを使用することはできません。

そのため、readObject() を呼び出す前に読み取るものがあるかどうかを確認する方法が必要です。これまでのところ、次の解決策を試しました。

解決策 1: ObjectInputStream.available() を使用して、読み取り可能なものがあるかどうかを確認します。ストリームにオブジェクトがあるかどうかに関係なく、このメソッドは常に 0 を返すように見えるため、このアプローチは失敗しました。したがって、これはまったく役に立ちません。

解決策 2: PushbackInputStream を使用して、ストリーム内の最初の未読バイトの存在を確認します。存在する場合はそれをプッシュバックし、ObjectInputStream を使用してオブジェクトを読み取ります。移動しない場合:

            boolean available;
            int b = pushbackinput.read();
            if (b==-1)
                  available = false;
            else
            {
                pushbackinput.unread(b);
                available = true;
            }
            if (available)
            {
            Object message= objectinput.readObject();
            // continue with what you need to do with that object
            }

読み取る入力がない場合にも read() がブロックされるため、これも役に立たないことが判明しました。ストリームが閉じられた場合にのみ -1 オプションを返すようです。ストリームがまだ開いているが空の場合、ブロックするだけなので、これは単純に ObjectInputStream.readObject(); を使用するのと同じです。

誰かが実際に機能するアプローチを提案できますか?

4

1 に答える 1

1

これは良い質問です。宿題をいくつかしました....しかし、物事を正しく行うには、いくつかの歴史をたどる必要があります。あなたの問題は、実際には ObjectInputStream ではなくソケットレベルの通信に関係していることに注意してください。

これまでの最も簡単な方法は、ソケットごとに個別のスレッドを用意することでした。これはある程度拡張可能でしたが、スレッドは高価で作成に時間がかかりました。

それに応じて、大規模なシステムでは、人々はスレッド プールを作成し、やるべき作業があるときにスレッドのソケットを処理していました。これは複雑でした。

その後、Java 言語は java.nio パッケージで変更され、ノンブロッキング IO とともにセレクターが導入されました。これにより、より少ないスレッドで複数のソケットにサービスを提供する信頼できる (場合によっては混乱を招く) 方法が作成されました。あなたのケースでは、「いくつかの」オブジェクトがあるときではなく、完全なオブジェクトを読み取る準備ができたときを知りたいので、それは完全には/あまり役に立ちません。

その間に「状況」が変化し、Java はより効率的にスレッドを作成および管理できるようになりました。「現在の」考え方は、ソケットごとに単一のスレッドを再度割り当てる方が優れている/高速で簡単であるということです....接続モデルごとのJavaスレッドとNIOを参照してください

あなたの場合、ソケットごとのスレッド モデルに固執することをお勧めします。Java はソケットよりも多くのスレッドを拡張および処理できるため、問題ありません。

于 2013-11-01T12:40:58.667 に答える