2011-02-19 26 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; 
    } 

}