2011-02-19 28 views
5

基本上,当有新消息发布时,我有一个从聊天室传输xml更新的URL。我希望将该URL转换为InputStream,并且只要保持连接并且只要我没有发送Thread.interrupt(),就可以继续读取它。我遇到的问题是BufferedReader.ready()在从流中读取内容时似乎不成立。如何从HttpsURLConnection创建Java无阻塞的InputStream?

我用下面的代码:

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()永远不会成为真正的,导致永远不会被读取的行。但是,如果我跳过“buf.ready()”部分并直接读取行,则会阻止进一步操作,直到读取行。

我该如何a)让buf.ready()返回true,或b)以防止阻塞的方式执行此操作?

由于提前, 詹姆斯

+1

每个连接都应该拆分成一个单独的线程。 – Nick 2011-02-19 06:48:08

回答

7

Reader.ready()当数据可以被读取而没有阻塞时返回true。期。 InputStreamsReaders正在阻止。期。这里的一切都按设计工作。如果你想要更多的并发这些API,你将不得不使用多个线程。或Socket.setSoTimeout()及其近似关系HttpURLConnection

+0

我知道我可以将事情分解成线程......这段代码已经在它自己的线程(runnable)对象中。我想要的是知道如何通过发送某种中断来停止线程。当输入流正在等待更多数据发布到流中时,它似乎阻止了其他所有内容,包括thread.interrupts。 – Warkior 2011-02-19 19:10:43

0

您可以使用Java NIO库提供非阻塞I/O能力。看看这篇文章的详细信息和示例代码:http://www.drdobbs.com/java/184406242

+0

这看起来像它有我正在寻找的手段导致线程超时,打破阻塞连接。去尝试一下。谢谢。 – Warkior 2011-02-19 19:27:20

+0

嗯。还没有设法找到一种方法来正确地中断被阻塞的线程。也许我只是做得不对。 – Warkior 2011-02-19 22:54:04

4

对于非阻塞IO,不要使用InputStream和Reader(或OutputStream/Writer),但使用java.nio.*类,在本例中为SocketChannel(和附加的CharsetDecoder)。


编辑:作为回答您的评论:

专找如何创建一个套接字通道上的HTTPS URL。

套接字(以及SocketChannels)在传输层(TCP)上工作,在应用层协议(如HTTP)下工作一个(或两个)级别。所以你不能创建一个套接字通道到https url

您将不得不打开一个套接字通道到正确的服务器和正确的端口(如果URI中没有其他东西,则为443),在客户端模式下创建一个SSLEngine(在javax.net.ssl中),然后读取来自通道的数据,将其提供给SSL引擎并以其他方式发送/从SSLEngine发送/接收正确的HTTP协议行,始终检查返回值以知道事实上处理了多少字节,以及下一步采取。

这个is quite complicated(我做过一次),如果你没有实现一个服务器同时连接很多客户端(你不能有一个单一的线程为每个连接)。相反,保留在您的阻止InputStream从URLConnection读取,并将其简单地放在一个备用线程,不妨碍其他应用程序。

0

使用通道没有HTTP/HTTPS实现。没有办法以非阻塞的方式从httpurlconnaction中读取输入流。您必须使用第三方库或者自己实现通过SocketChannel的http。

0
import java.io.IOException; 
import java.io.InputStream; 
import java.util.Arrays; 

/** 
* This code demonstrates non blocking read from standard input using separate 
* thread for reading. 
*/ 
public class NonBlockingRead { 

    // Holder for temporary store of read(InputStream is) value 
    private static String threadValue = ""; 

    public static void main(String[] args) throws InterruptedException { 

     NonBlockingRead test = new NonBlockingRead(); 

     while (true) { 
      String tmp = test.read(System.in, 100); 
      if (tmp.length() > 0) 
       System.out.println(tmp); 
      Thread.sleep(1000); 
     } 
    } 

    String read(final InputStream is, int timeout) { 
     // Start reading bytes from stream in separate thread 
     Thread thread = new Thread() { 
      public void run() { 
       byte[] buffer = new byte[1024]; // read buffer 
       byte[] readBytes; // holder of actually read bytes 
       try { 
        // Read available bytes from stream 
        int size = is.read(buffer); 
        if (size > 0) { 
         if (size > 1) 
          readBytes = Arrays.copyOf(buffer, size - 1); 
         else 
          readBytes = new byte[0]; 
         // and save read value in static variable 
         setValue(new String(readBytes, "UTF-8")); 
        } 
       } catch (IOException e) { 
        System.err.println("Data reading error: " + e); 
       } 
      } 
     }; 
     thread.start(); // Start thread 
     try { 
      thread.join(timeout); // and join it with specified timeout 
     } catch (InterruptedException e) { 
      System.err.println("Data were note read in " + timeout + " ms"); 
     } 
     return getValue(); 
    } 

    private synchronized void setValue(String value) { 
     threadValue = value; 
    } 

    private synchronized String getValue() { 
     String tmp = new String(threadValue); 
     setValue(""); 
     return tmp; 
    } 

}