3

SocketChannel.write() を介して大量のデータを送信しているときに、基礎となる TCP バッファーがいっぱいになることがあります。データがすべて送信されるまで、write() を継続的に再試行する必要があります。

だから、私はこのようなものを持っているかもしれません:

public void send(ByteBuffer bb, SocketChannel sc){
   sc.write(bb);
   while (bb.remaining()>0){
      Thread.sleep(10);
      sc.write(bb);          
   }
}

問題は、大規模な ByteBuffer と基礎となる TCP バッファのオーバーフローが時折発生する問題であり、send() へのこの呼び出しが予期しない時間にわたってブロックされることを意味します。私のプロジェクトでは、何百ものクライアントが同時に接続されており、1 つのソケット接続によって引き起こされる 1 つの遅延により、1 つの SocketChannel によるこの 1 つの遅延が解決されるまで、システム全体がクロール状態になる可能性があります。遅延が発生すると、プロジェクトの他の領域で速度が低下するという連鎖反応が発生する可能性があり、遅延が少ないことが重要です。

この TCP バッファ オーバーフローの問題を透過的に処理し、SocketChannel.write() への複数の呼び出しが必要な場合にすべてをブロックすることのないソリューションが必要です。send() を Thread を拡張する別のクラスに配置して、独自のスレッドとして実行し、呼び出し元のコードをブロックしないようにすることを検討しました。ただし、維持している各ソケット接続のスレッドを作成する際に必要なオーバーヘッドが心配です。特に、99% の確率で SocketChannel.write() が最初の試行で成功する場合、スレッドが存在する必要がないことを意味します。 . (つまり、send() を別のスレッドに配置する必要があるのは、while() ループが使用されている場合のみです。バッファの問題が発生した場合のみ、おそらく 1% の時間です) バッファの問題がある場合1%の確率で、私はそうしません

それが理にかなっていることを願っています...いくつかの提案を実際に使用できます。ありがとう!

4

6 に答える 6

1

Java NIO以前は、良好なパフォーマンスを得るには、ソケットごとに1つのスレッドを使用する必要がありました。これは、Javaだけでなく、すべてのソケットベースのアプリケーションにとって問題です。これを克服するために、ノンブロッキングIOのサポートがすべてのオペレーティングシステムに追加されました。JavaNIOの実装はに基づいていSelectorsます。

開始するには、最も信頼のおけるJavaNIOブックとこのOnJavaの記事を参照してください。ただし、これは複雑なトピックであり、コードにマルチスレッドの問題が発生することに注意してください。詳細については、Googleの「ノンブロッキングNIO」を参照してください。

于 2009-07-18T16:10:39.253 に答える
1

Java NIO について読めば読むほど、意気消沈します。とにかく、この記事はあなたの問題を解決すると思います...

http://weblogs.java.net/blog/2006/05/30/tricks-and-tips-nio-part-i-why-you-must-handle-opwrite

この男は、睡眠ループよりも洗練された解決策を持っているようです。

また、Java NIO を単独で使用するのは危険すぎるという結論に達しつつあります。可能な限り、Java NIO とその小さな「驚き」の上に優れた抽象化を提供する Apache MINA をおそらく使用すると思います。

于 2010-02-24T20:40:00.227 に答える
0

Selector.select()を使用したループがすでにあると仮定すると、実行する必要のあることがいくつかあります。I/Oの準備ができているソケットを判別します。

  • ソケットチャネルを作成した後、非ブロッキングに設定します。sc.configureBlocking(false);
  • バッファ(おそらくその一部)を書き込み、何かが残っているかどうかを確認します。バッファ自体が現在の位置と残りの量を処理します。

何かのようなもの

sc.write(bb);
if(sc.remaining() == 0)
   //we're done with this buffer, remove it from the select set if there's nothing else to send.
else
    //do other stuff/return to select loop
  • 眠っているwhileループを取り除く
于 2009-07-18T17:44:17.440 に答える
0

私は今、同じ問題のいくつかに直面
しています。-接続数が少ないが転送が多い場合は、スレッドプールを作成し、ライタースレッドの書き込みをブロックします。
-接続が多い場合は、完全なJava NIOを使用し、accept()されたソケットにOP_WRITEを登録して、セレクターが入るのを待つことができます。

OriellyJavaNIOの本にはこれらすべてがあります。
また: http ://www.exampledepot.com/egs/java.nio/NbServer.html?l = rel

オンラインでの調査の結果、多くの着信接続がない限り、NIOはかなりやり過ぎだと私は信じています。それ以外の場合、大きな転送が数回しかない場合は、書き込みスレッドを使用します。おそらくより迅速な応答があります。多くの人が、NIOが希望する速さで応答しないという問題を抱えています。あなたの書き込みスレッドはそれ自身でブロックしているので、それはあなたを傷つけることはありません。

于 2009-07-18T17:44:39.517 に答える
0

書き込みはすぐに戻るかブロックされるため、sleep()は必要ありません。初めて書き込みを行わない場合は、書き込みを渡すエグゼキュータを使用できます。もう1つのオプションは、書き込みを実行するためのスレッドの小さなプールを用意することです。

ただし、(提案されているように)セレクターを使用して、ソケットが別の書き込みを実行する準備ができたことを確認するのが最善のオプションです。

于 2009-07-18T16:16:24.030 に答える
0

何百もの接続の場合、おそらく NIO を気にする必要はありません。古き良きブロッキングソケットとスレッドで十分です。

NIO ではOP_WRITE、選択キーに関心を登録することができ、さらにデータを書き込む余地があるときに通知を受け取ることができます。

于 2009-07-18T17:22:27.110 に答える