web-dev-qa-db-ja.com

javaソケット/出力ストリーム書き込み:それらはブロックしますか?

出力ストリームのソケットにのみ書き込みを行っている場合、ブロックすることはありますか?ブロックできるのは読み取りのみです。誰かが書き込みをブロックできると私に言ったが、私はソケットのreadメソッドのタイムアウト機能しか見ない-Socket.setSoTimeout()

書き込みがブロックされても意味がありません。

36
jbu

特にTCPソケットの場合、ソケットへの書き込みもブロックできます。OSは、一定量の未送信(または送信されたが未確認)データのみをバッファします。リモートアプリはそれを読み取ることができ、ソケットは最終的にバックアップし、write呼び出しはブロックされます。

これらのフォローアップの質問への応答:

これにタイムアウトを設定するメカニズムはありますか?私はそれがどのような振る舞いをするのか分かりません...バッファがいっぱいになるとデータを捨てるかもしれません?または、おそらくバッファ内の古いデータを削除しますか?

Java.net.Socketに書き込みタイムアウトを設定するメカニズムはありません。 Socket.setSoTimeout()メソッドがありますが、これはaccept()呼び出しではなくread()呼び出しとwrite()呼び出しに影響します。どうやら、NIO、非ブロッキングモード、セレクターを使用すると書き込みタイムアウトが発生する可能性がありますが、これは想像するほど便利ではありません。

適切に実装されたTCPスタックは、接続が閉じられない限り、バッファされたデータを破棄しません。ただし、書き込みタイムアウトが発生した場合、現在OSレベルのバッファにあるデータが他の問題は、最後のwriteから実際にOSレベルに転送されたデータの量がわからないということですTCPスタックバッファ。ストリームを再同期するためのアプリケーションレベルのプロトコルがありません*writeのタイムアウト後に安全に行う唯一のことは、接続をシャットダウンすることです。

対照的に、UDPソケットを使用する場合、write()呼び出しは、かなりの時間ブロックされません。ただし、ネットワークの問題があるか、リモートアプリケーションが追いついていない場合、メッセージはフロアにドロップされ、どちらの側にも通知されません。さらに、メッセージがリモートアプリケーションに順不同で配信されることがあります。これらの問題に対処するのはあなた(開発者)です。

*これは理論的には可能ですが、ほとんどのアプリケーションでは、すでに信頼できる(ある程度の)TCP/IPストリームに加えて追加の再同期メカニズムを実装しても意味がありません。そして、それが理にかなっている場合は、接続が閉じられた可能性にも対処する必要があります。そのため、assume閉じた方が簡単です。

49
Stephen C

これを行う唯一の方法は、NIOとセレクターを使用することです。

このバグレポートで、Sun/Oracleエンジニアの記事をご覧ください。 http://bugs.Sun.com/bugdatabase/view_bug.do?bug_id=40311

7
Noel Grandin