2016-06-16 7 views
1

複数のクライアントがサーバーに接続し、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(); 
      } 
     } 
    } 
+0

NB 'readObject()'は、nullを送信しない限り、nullを返しません。あなたがそれを行うことを計画していないなら、ヌルテストは無意味です。 – EJP

答えて

0

差出人あなただけのTCPの動作を説明してきました受信者を凌駕します。受信者は送信者に送信を停止するように指示するので、送信者は送信を停止します。ブロッキングI/Oを使用している場合、クライアントは内部でsend()をブロックします。

ここで問題は解決しません。

+0

いいえ、そうではありません。サーバーは単一のクライアントで25K/sをうまく処理しますが、2Kで1K /秒でフリーズします。 – Andrey

+1

したがって、サーバーで並行性に問題があります。 – EJP

-1

問題は、サーバ側のハンドラがスレッドセーフではないリソース(Jedis接続など)を使用していたため、サーバ側ですべてスタックされていたことです。

スレッドセーフを行うと問題が解決しました。

+0

これで21ヵ月前と同じように、サーバーに並行性の問題が発生しました。 – EJP

+0

正しい、あなたのコメントに+1がある – Andrey

+0

なぜ私はあなたに21ヶ月前にすでに話したことを言っているのですか? – EJP

関連する問題