我有一个麻烦问题,就是从一个运行在Linux上的Java(NIO)服务器快速连续地向客户端发送多个大型消息会导致数据包被截断。必须发送大型消息并且速度非常快才会有这个问题发生。这里基本上是我的代码在做什么(不是实际代码,但大致描述了正在发生的情况):
//-- 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+ ));
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缓冲区或“窗口大小”有关,或者说这里的服务器只是提供数据比操作系统、网络适配器或其他工具更快,导致它无法处理。但是我该如何检查并防止它发生呢?如果我减少每次使用sc.write()的消息长度,但是然后增加重复次数,我仍然会遇到同样的问题。它似乎只是在短时间内有大量数据的问题。我也没有看到sc.write()抛出任何异常(我知道在上面的示例中我没有检查,但是在我的测试中有检查)。
如果我能以编程方式检查它是否还没有准备好更多数据,并进行延迟,等待它准备好,那我会很高兴。我也不确定"sc.socket().setSendBufferSize(1024* 1024);"是否有任何效果,或者我需要在Linux端进行调整。有没有一种真正"清除" SocketChannel 的方法?作为一个笨拙的解决方案,我可以尝试在发送超过10KB的消息时强制发送任何缓冲区中的内容(在我的应用程序中并不经常发生)。但我不知道是否有一种方法来强制发送缓冲区(或等待它发送完)。谢谢任何帮助!