将InputStream(阻塞)的内容写入非阻塞套接字

3
我正在编写一个简单的Java NIO服务器,但有一个小问题:我需要将普通的InputStream管道传输给我的客户端。我有一个单独的线程执行所有的写操作,这就产生了一个问题:如果InputStream阻塞,所有其他连接的写入都将被暂停。
我可以使用InputStream.available()检查是否有任何可读取的传入数据而不会阻塞,但是如果已经到达流的末尾,似乎我必须调用read()才能知道。
这对我来说造成了很大的困扰,但我不可能相信我是第一个遇到这个问题的人。
迄今为止,我想到的唯一选择是:
  • 为每个InputStream单独开辟一个线程,但这太愚蠢了,因为我一开始就使用非阻塞I/O。我也可以使用线程池来完成这个任务,但这又限制了我可以同时传输InputStream的客户端数量。
  • 使用具有超时的单独线程读取这些流(使用另一个线程在读取时间超过一定时间后中断),但这肯定会妨碍数据流,特别是当我有许多打开的InputStream未传输数据时。
当然,如果有一个神奇的InputStream.isEof()isClosed(),那么这将不会是任何问题了 :'(

1
使用阻塞IO一点也不傻。你可以获得与之同等或更好的性能。你知道这实际上是一个问题吗? - Peter Lawrey
是的,服务器需要支持大量的持久连接(20,000+)。 - Arne
你不能以非阻塞的方式使用InputStream,这是无法避免的。我建议你替换掉提供InputStream的系统或者像你已经做的那样使用多个线程。这些线程可能有多少?如果少于1K,我就不会担心它。 - Peter Lawrey
如果您有超过10K的连接,是否考虑使用多台服务器? - Peter Lawrey
使用多台服务器当然是可能的,但这需要我编写更多的代码,因为其中一些连接通过服务器进行互相通信。当然,没有什么是不可能的,但我宁愿不重写整个程序 :) - 而且我预算有限。 - Arne
2个回答

3
"每个InputStream都有一个单独的线程,但这只是愚蠢的,因为我一开始就使用了非阻塞I/O。"并不愚蠢。首先,您需要检查您的InputStream实现是否可以检索SelectableChannel。如果可以,那么您很幸运,可以像往常一样将其注册到选择器中。但是,您的InputStream可能具有不是SelectableChannel的通道,此时“每个InputStream都有一个单独的线程”是明显的选择,也可能是正确的选择。
请注意,在SO上讨论了类似的问题(无法从输入流获取SelectableChannel)。不幸的是您被卡住了。"

谢谢,我现在已经明白我需要什么了! - Arne
“你是否可以从你的InputStream实现中检索SelectableChannel” - 只有当套接字由SocketChannel.open()或ServerSocketChannel.accept()创建时,才能从套接字获取通道。这在Javadoc中有说明。运气与此无关。 - user207421

-1
我有一个单线程执行所有写操作。
你是否考虑过这是问题的一部分,而不是解决方案的一部分?

1
我不能为每个连接创建一个线程,因为我需要支持大量的并发连接。 - Arne
@Arne:非正常情况。 在正确的硬件和操作系统支持下,现代JVM可以支持多少线程,你会感到惊讶的。 - user207421
是的,我看到了正在进行的讨论。我不知道足够多的信息来发表意见,我只需要它能够直接开箱即用,而且使用低内存量,无需调整操作系统或其他任何东西。然而,你也可以指出这样的服务器应该使用Erlang制作,而我使用Java是个白痴...等等,这个列表还可以继续 :) - Arne
@Peter 绝对没错,那是明智的选择,我可能会这样做,但问题仍然存在 :( - Arne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接