複数のクライアントがサーバーに接続し、TCP接続を介してサーバーにシリアル化されたオブジェクトを高速に送信するクライアント/サーバーアプリケーションを作成しています。ObjectOutputStream 2つのクライアントがサーバーにオブジェクトを送信すると、writeObjectがハングする
クライアントでObjectOutputStream.writeObjectを使用し、サーバーでObjectInputStream.readObjectを使用しています。
サーバアプリケーションは、serverSocket.accept()を使用して単一ポート上でクライアント接続を受け入れ、Socketをオブジェクトを読み取るための新しいスレッドに渡します。
単一のクライアントが約25Kのオブジェクトを接続して送信すると、すべて正常に動作します。短時間のうちに2番目のクライアントを起動すると、一方または両方のクライアントがサーバーの1つのObjectOutputStream.writeObjectにハングし、対応するサーバーがObjectInputStream.readObjectでハングします。 両側に例外がスローされません。
レートが非常に低い場合、合計で10-20/sと言えます。ハングしませんが、100-1000/sになります。
クライアントマシンでnetstat -an
を使用すると、対応するリンクのsend-Q
が約30Kであることがわかります。サーバー側ではreceive-Q
も〜30Kです。
ローカルWindows上でクライアント/サーバーを実行しているときに、クライアントがハングするが、サーバーが受信オブジェクトを処理し続け、キャッチするとクライアントはロックを解除してオブジェクトの送信を続行します。
ローカルでは、サーバーはクライアントよりも低速ですが、Linuxでは、異種マシン上で実行されているサーバーインスタンスの数は、クライアントが生成する速度以上です。
何が起こっているのか?
クライアントコードスニップ:接続を受け入れる
Socket socket = new Socket(address, port);
ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
while(true)
{
IMessage msg = createMsg();
outputStream.writeObject(msg);
outputStream.flush();
outputStream.reset();
}
サーバコード:
while(active)
{
Socket socket = serverSocket.accept();
SocketThread socketThread = new SocketThread(socket);
socketThread.setDaemon(true);
socketThread.start();
}
サーバーコードオブジェクトの読み込み:
public class SocketThread extends Thread
{
Socket socket;
public SocketThread(Socket socket)
{
this.socket = socket;
}
@Override
public void run() {
try {
ObjectInputStream inStream = new ObjectInputStream(socket.getInputStream());
while(true)
{
IMessage msg = (IMessage)inStream.readObject();
if(msg == null){
continue;
}
List<IMessageHandler> handlers = handlersMap.get(msg.getClass());
for(IMessageHandler handler : handlers){
handler.onMessage(msg);
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
NB 'readObject()'は、nullを送信しない限り、nullを返しません。あなたがそれを行うことを計画していないなら、ヌルテストは無意味です。 – EJP