如何从 HttpsURLConnection 创建 Java 非阻塞输入流?
基本上,我有一个 URL,用于在发布新消息时从聊天室传输 xml 更新。我想将该 URL 转换为 InputStream,并在保持连接且未发送 Thread.interrupt() 的情况下继续从中读取数据。我遇到的问题是,当有内容要从流中读取时,BufferedReader.ready() 似乎不会变为 true。
我使用以下代码:
BufferedReader buf = new BufferedReader(new InputStreamReader(ins));
String str = "";
while(Thread.interrupted() != true)
{
connected = true;
debug("Listening...");
if(buf.ready())
{
debug("Something to be read.");
if ((str = buf.readLine()) != null) {
// str is one line of text; readLine() strips the newline character(s)
urlContents += String.format("%s%n", str);
urlContents = filter(urlContents);
}
}
// Give the system a chance to buffer or interrupt.
try{Thread.sleep(1000);} catch(Exception ee) {debug("Caught thread exception.");}
}
当我运行代码并将某些内容发布到聊天室时, buf.ready() 永远不会变为 true,导致这些行永远不会被读取。但是,如果我跳过“buf.ready()”部分并直接读取行,它将阻止进一步的操作,直到读取行。
我如何 a) 让 buf.ready() 返回 true,或 b) 以防止阻塞的方式执行此操作?
提前致谢, 詹姆斯
Basically, I have a URL that streams xml updates from a chat room when new messages are posted. I'd like to turn that URL into an InputStream and continue reading from it as long as the connection is maintained and as long as I haven't sent a Thread.interrupt(). The problem I'm experiencing is that BufferedReader.ready() doesn't seem to become true when there is content to be read from the stream.
I'm using the following code:
BufferedReader buf = new BufferedReader(new InputStreamReader(ins));
String str = "";
while(Thread.interrupted() != true)
{
connected = true;
debug("Listening...");
if(buf.ready())
{
debug("Something to be read.");
if ((str = buf.readLine()) != null) {
// str is one line of text; readLine() strips the newline character(s)
urlContents += String.format("%s%n", str);
urlContents = filter(urlContents);
}
}
// Give the system a chance to buffer or interrupt.
try{Thread.sleep(1000);} catch(Exception ee) {debug("Caught thread exception.");}
}
When I run the code, and post something to the chat room, buf.ready() never becomes true, resulting in the lines never being read. However, if I skip the "buf.ready()" part and just read lines directly, it blocks further action until lines are read.
How do I either a) get buf.ready() to return true, or b) do this in such a way as to prevent blocking?
Thanks in advance,
James
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
你不能。你的问题体现了一个术语上的矛盾。 Java 中的流是阻塞的。因此,不存在“非阻塞
InputStream
”这样的东西。当可以无阻塞地读取数据时,
Reader.ready()
返回 true。时期。InputStreams
和Readers
正在阻塞。时期。这里的一切都按设计进行。如果您希望这些 API 具有更多并发性,则必须使用多个线程。或者Socket.setSoTimeout()
及其在HttpURLConnection
中的密切关系。You can't. Your question embodies a contradiciton in terms. Streams in Java are blocking. There is therefore no such thing as a 'non-blocking
InputStream
'.Reader.ready()
returns true when data can be read without blocking. Period.InputStreams
andReaders
are blocking. Period. Everything here is working as designed. If you want more concurrency with these APIs you will have to use multiple threads. OrSocket.setSoTimeout()
and its near relation inHttpURLConnection
.对于非阻塞 IO,不要使用 InputStream 和 Reader(或 OutputStream/Writer),而是使用 java.nio.* 类,在本例中是 SocketChannel(以及附加的字符集解码器)。
编辑:作为对您评论的答复:
套接字(以及 SocketChannel)在传输层 (TCP) 上工作,传输层位于应用层协议(例如 HTTP)之下的一(或两)层。因此您无法创建到 https url 的套接字通道。
相反,您必须打开到正确服务器和正确端口的 Socket-Channel(如果 URI 中没有给出其他内容,则为 443),在客户端模式下创建 SSLEngine(在 javax.net.ssl 中),然后从通道读取数据,将其提供给 SSL 引擎,反之亦然,并向您的 SSLEngine 发送/获取正确的 HTTP 协议行,始终检查返回值以了解实际上处理了多少字节以及下一步是什么拿。
这相当复杂(我做到了一次),如果您没有实现同时连接大量客户端的服务器(其中每个连接不能有一个线程),那么您实际上并不想这样做。相反,保留从 URLConnection 读取的阻塞 InputStream,并将其简单地放在不会妨碍应用程序其余部分的备用线程中。
For nonblocking IO don't use InputStream and Reader (or OutputStream/Writer), but use the
java.nio.*
classes, in this case aSocketChannel
(and additional a CharsetDecoder).Edit: as an answer to your comment:
Sockets (and also SocketChannels) work on the transport layer (TCP), one (or two) level(s) below application layer protocols like HTTP. So you can't create a socket channel to an https url.
You would instead have to open a Socket-Channel to the right server and the right port (443 if nothing else given in the URI), create an SSLEngine (in javax.net.ssl) in client mode, then read data from the channel, feeding it to the SSL engine and the other way around, and send/get the right HTTP protocol lines to/from your SSLEngine, always checking the return values to know how many bytes were in fact processed and what would be the next step to take.
This is quite complicated (I did it once), and you don't really want to do this if you are not implementing a server with lots of clients connected at the same time (where you can't have a single thread for each connection). Instead, stay with your blocking InputStream which reads from your URLConnection, and put it simply in a spare thread which does not hinder the rest of your application.
您可以使用提供非阻塞 I/O 功能的 Java NIO 库。请参阅本文以获取详细信息和示例代码: http://www.drdobbs.com/java/184406242 。
You can use the Java NIO library which provides non-blocking I/O capabilities. Take a look at this article for details and sample code: http://www.drdobbs.com/java/184406242.
没有使用通道的 HTTP/HTTPS 实现。无法以非阻塞方式从 httpurlconnaction 读取输入流。您要么必须使用第三方库,要么自己通过 SocketChannel 实现 http。
There is no HTTP/HTTPS implementation using Channels. There is no way to read the inputstream from a httpurlconnaction in a non-blocking way. You either have to use a third party lib or implement http over SocketChannel yourself.