2012-03-12 81 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