SocketChannel.write() 的 Java NIO 线程问题

标签 java sockets nio

有时,在通过 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() 的调用将阻塞一段意想不到的时间。在我的项目中,有数百个客户端同时连接,一个套接字连接引起的一次延迟可以使整个系统爬行,直到解决一个 SocketChannel 的延迟。发生延迟时,可能会导致项目其他领域的链式 react 变慢,低延迟很重要。

我需要一个解决方案来透明地处理这个 TCP 缓冲区溢出问题,并且在需要多次调用 SocketChannel.write() 时不会导致所有内容阻塞。我考虑过将 send() 放入一个扩展 Thread 的单独类中,以便它作为自己的线程运行并且不会阻止调用代码。但是,我担心为我维护的每个套接字连接创建线程所需的开销,尤其是在 99% 的情况下,SocketChannel.write() 在第一次尝试时成功,这意味着线程不需要存在. (换句话说,只有在使用 while() 循环时才真正需要将 send() 放在单独的线程中——仅在存在缓冲区问题的情况下,可能只有 1% 的时间)如果存在缓冲区问题只有 1% 的时间,我不需要线程的开销来处理其他 99% 的 send() 调用。

我希望这是有道理的...我真的可以使用一些建议。谢谢!

最佳答案

在 Java NIO 之前,您不得不为每个套接字使用一个线程以获得良好的性能。这是所有基于套接字的应用程序的问题,而不仅仅是 Java。为所有操作系统添加了对非阻塞 IO 的支持以克服这个问题。 Java NIO 实现基于Selectors

参见 The definitive Java NIO book还有这个On Java文章开始。但是请注意,这是一个复杂的主题,它仍然会给您的代码带来一些多线程问题。谷歌“非阻塞 NIO”了解更多信息。

关于SocketChannel.write() 的 Java NIO 线程问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1147873/

相关文章:

java - 当主类尝试调用另一个类的私有(private)方法时如何抛出异常?

c - 程序写入socket后自动关闭

javascript - Node Socket.IO socket.on() 跨多个文件

java - 如何将一定数量的字节读入缓冲区?

java - 随机访问中的 FileChannel 与 MappedByteBuffer?

java - 用特定的单个字符替换给定字符串的所有字符

java - 从 ArrayList 中删除整数 IndexOutOfBoundsException

java - 计时器需要很长时间才能启动

ios - 在 iPhone 和 macbook 笔记本电脑之间进行通信

java 网络,写入调用平均比读取调用长 4 倍,这正常吗?