同時に複数のクライアントと通信するサーバーを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(); を使用するのと同じです。
誰かが実際に機能するアプローチを提案できますか?