2012-05-13 16 views
9

私は現在、プロジェクトのために素朴なネットワークコードを書いています。メイトは、サーバからすべてのクライアントに情報のパッケージを反復的に送信すると、クライアントが正しく応答していません。JavaでOutputStreamがブロックされていますか?

彼はトローリングで知られているので、クライアントにデータを送信する役割を担うセカンダリスレッドを実装するときには懐疑的でした。サーバは単にスレッドを読み取ってパッケージを追加するだけですデータを送信する。

Java SocketのOutputStreamは実際に天気かどうかを考えた後、実際にキューに入れたいものをキューに入れるので、あらかじめキューが不要です。送信されたオブジェクトが受信されたというクライアントからの応答を取得しない限り、サーバーがブロックしている場合にのみ、激しい問題が発生する可能性があります。

ありがとうございました。

+0

スレッドの実行機能で出力ストリームまたは入力ストリームを取得しようとすると、同様の問題が発生しました。ソケットのgetInputStreamとgetOutputStreamの両方に対するブロッキングの問題は、実行関数内にあるためです。解決策はコンストラクタに変数を保存してから、変数を実行中に参照することです。 – Zimm3r

答えて

4

もちろん、ソケットに書き込むと、この書き込みはバッファされます。 Socketオブジェクトには、このバッファサイズを設定する方法があります(setSendBufferSize())。あなたの書き込みがこのバッファにキャッシュされていれば、もちろん、次のソケットで直ちに反復処理を行うことができます。それ以外の場合は、このバッファをすぐにクライアントにフラッシュする必要があります。したがって、フラッシュ中にブロックされることになります。バッファをフラッシュする際にブロックされないようにするには、非ブロックI/OでSocketChannelを使用する必要があります。 とにかく、同時に多くのソケットに書き込むための最良の方法は、すべての書き込みが同時に実行されるように、別のスレッドで各ソケットを管理することです。

+5

"それ以外の場合は、このバッファをすぐにクライアントにフラッシュする必要があります"という正しい方法はありません。バッファは常に非同期的にネットワークに書き込まれますが、ピアの受信バッファに空きがなくなるまでは送信できません。ピアが読み込み中でない場合、または読み込み速度が遅い場合、受信バッファがいっぱいになるので、送信バッファがいっぱいになるため、後続の書き込みがブロックされます。 – EJP

+0

Tomaszの記事がより良い例だったにもかかわらず、これはまさに私がEJPの説明の点で探していたものです。どうもありがとうございました。 – salbeira

8

あなたの友人は正しいですが、それはどのようにしてプロトコルが動作するかに関係します。クライアントに送信されるパケットを大幅に単純化する必要があります。クライアントが応答していない場合(受信データの読み取りに失敗し、コンピュータの負荷が高いなど)、サーバーは確認応答を受信せず、データの送信を停止します。 TCP/IPに組み込まれているこのメカニズムは、通信の一方の端が大量のデータを送信することを防止し、他方の端が受信したことを確認しません。これにより、大量のデータを再送信する必要がなくなります。

Javaでは、これはブロッキング書き込みとしてOutputStreamに現れます。基礎となるTCP/IPスタック/オペレーティングシステムでは、クライアントがデータを受信する準備ができるまで、より多くのデータを送信することはできません。

これは簡単にテストできます。私は、接続を受け入れますが、受信データの読み取りに失敗し、単純なサーバーを実装:

new Thread(new Runnable() { 
    @Override 
    public void run() { 
     try { 
      final ServerSocket serverSocket = new ServerSocket(4444); 
      final Socket clientSocket = serverSocket.accept(); 
      final InputStream inputStream = clientSocket.getInputStream(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

    } 
}).start(); 

そして、ちょうど4Kバッチで、それはできるだけ多くのデータを送信し、簡単なクライアント:

final Socket client = new Socket("localhost", 4444); 
final OutputStream outputStream = client.getOutputStream(); 
int packet = 0; 
while(true) { 
    System.out.println(++packet); 
    outputStream.write(new byte[1024 * 4]); 
} 

クライアントループがオンにハングアップします私のコンピュータは95回の繰り返しの後で(あなたの走行距離は異なるかもしれません)。しかし、サーバスレッドでinputStreamから読んだ場合、ループが繰り返し実行されます。

+0

スレッドの実行機能で出力または入力ストリームを取得しようとすると、同様の問題が発生しました。ソケットのgetInputStreamとgetOutputStreamの両方に対するブロッキングの問題は、実行関数内にあるためです。解決策はコンストラクタに変数を保存してから、変数を実行中に参照することです。 – Zimm3r

0

出力ストリームがブロックされています。おそらくいくつかのバッファリングがありますが、サーバがバイトを消費することは決してありません(すべての固定バッファが最終的にいっぱいになります)。あなたの友人は正しいので、別のスレッドで書くか、nioのようなより高度なものを使う必要があります。

読み取り側でavailable()を使用すると、ブロックされないようにすることができます。書き込み側に一致する呼び出しが存在しません。私はそこにいたかった。

関連する問題