Java(NIO)サーバー(Linuxを実行している)からクライアントに複数の大きなメッセージをすばやく連続して送信すると、パケットが切り捨てられるという厄介な問題があります。問題が発生するには、メッセージが大きく、非常に迅速に送信される必要があります。これが基本的に私のコードが行っていることです(実際のコードではありませんが、多かれ少なかれ何が起こっているのか):
//-- setup stuff: --
Charset charset = Charset.forName("UTF-8");
CharsetEncoder encoder = charset.newEncoder();
String msg = "A very long message (let's say 20KB)...";
//-- inside loop to handle incoming connections: --
ServerSocketChannel ssc = (ServerSocketChannel)key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.socket().setTcpNoDelay(true);
sc.socket().setSendBufferSize(1024*1024);
//-- later, actual sending of messages: --
for (int n=0; n<20; n++){
ByteBuffer bb = encoder.encode(CharBuffer.wrap(msg+'\0'));
sc.write(bb);
bb.rewind();
}
したがって、パケットが十分に長く、可能な限り迅速に送信される場合(つまり、遅延のないこのようなループで)、もう一方の端では、次のような結果になることがよくあります。
[COMPLETE PACKET 1]
[COMPLETE PACKET 2]
[COMPLETE PACKET 3]
[START OF PACKET 4][SOME OR ALL OF PACKET 5]
データが失われ、パケットが一緒に実行され始めます。そのため、パケット5の開始(この例では)は、パケット4の開始と同じメッセージで到着します。切り捨てるだけでなく、メッセージを一緒に実行します。
これはTCPバッファまたは「ウィンドウサイズ」に関連していると思います。または、ここのサーバーは、OSやネットワークアダプタなどが処理できるよりも高速にデータを提供しているだけだと思います。しかし、どうすればそれをチェックして、それが起こらないようにすることができますか?sc.write()を使用するたびにメッセージの長さを減らしても、繰り返しを増やしても、同じ問題が発生します。短時間でのデータ量の問題に過ぎないようです。sc.write()が例外をスローしていることもわかりません(上記の例ではチェックしていませんが、テストにはあります)。
プログラムでデータの準備ができていないかどうかをプログラムで確認し、遅延を入れて、準備ができるまで待つことができれば幸いです。「sc.socket()。setSendBufferSize(1024 * 1024);」かどうかもわかりません。何らかの効果があります。または、Linux側でこれを調整する必要がある場合。SocketChannelを実際に「フラッシュ」する方法はありますか?不十分な回避策として、たとえば10KBを超えるメッセージを送信しようとしているときはいつでも、バッファリングされているものを明示的に完全に送信しようとすることができます(これは私のアプリケーションではそれほど頻繁ではありません)。しかし、バッファの送信を強制する(または送信されるまで待つ)方法はわかりません。助けてくれてありがとう!