2012-03-12 62 views
8

我正在開發服務器客戶端應用程序,並且在等待輸入流上的輸入數據時遇到問題。Java InputStream等待數據。

我有專用於讀取輸入數據的線程。目前它使用while循環來保持數據可用。 (N.B.協議如下:發送數據包的大小,比如說N,然後發送N個字節)。

public void run(){ 
    //some initialization 
    InputStream inStream = sock.getInputStream(); 
    byte[] packetData; 
    //some more stuff 
    while(!interrupted){ 
     while(inStream.available()==0); 
     packetData = new byte[inStream.read()]; 
     while(inStream.available()<packetData.length); 
     inStream.read(packetData,0,packetData.length); 
     //send packet for procession in other thread 
    } 
} 

它的工作原理,但通過while循環阻塞線程是一個壞主意。我可以使用Thread.sleep(X)來防止循環連續消耗資源,但肯定有更好的方法。

另外我不能依賴InputStream.read來阻塞線程,因爲數據的一部分可能由服務器發送延遲。我嘗試過,但總是會導致意外的行爲。

我會很感激的任何想法:)

+2

InputStream.read已經當數據不可用塊。所以放棄'可用'方法。 – UmNyobe 2012-03-12 12:17:43

回答

12

您可以使用DataInputStream.readFully()

DataInputStream in = new DataInputStream(sock.getInputStream()); 
//some more stuff 
while(!interrupted) { 
    // readInt allows lengths of up to 2 GB instead of limited to 127 bytes. 
    byte[] packetData = new byte[in.readInt()]; 
    in.readFully(packetData); 
    //send packet for procession in other thread 
} 

我更喜歡使用阻塞NIO支持可重用的緩衝區。

SocketChannel sc = 
ByteBuffer bb = ByteBuffer.allocateDirect(1024 *1024); // off heap memory. 

while(!Thread.currentThread.isInterrupted()) { 
    readLength(bb, 4); 
    int length = bb.getInt(0); 
    if (length > bb.capacity()) 
     bb = ByteBuffer.allocateDirect(length); 
    readLength(bb, length); 
    bb.flip(); 
    // process buffer. 
} 



static void readLength(ByteBuffer bb, int length) throws EOFException { 
    bb.clear(); 
    bb.limit(length); 
    while(bb.remaining() > 0 && sc.read(bb) > 0); 
    if (bb.remaining() > 0) throw new EOFException(); 
} 
+3

您可能不想將2GiB讀入您的內存 – 2015-03-26 23:37:28

4

正如UmNyobe說,available()是爲了使用,如果你希望阻止的默認行爲是阻塞。

只需使用普通的read讀取任何可用的,但在其他線程一旦你有你的緩衝區packetData.length字節處理僅發送信息包...

+0

謝謝......保存了我的一天。 – Velu 2015-08-04 09:11:04