Java InputStream等待数据。

13
我正在开发服务器-客户端应用程序,但在等待输入流数据方面遇到了问题。
我有一个专门用于读取输入数据的线程。目前它使用while循环来等待数据是否可用。(注意:协议如下:先将数据包大小作为int发送,然后发送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方法在数据不可用时已经会阻塞,因此可以忽略available方法。 - UmNyobe
2个回答

15

你可以使用 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();
}

7
如UmNyobe所说,available()的意思是如果您不想阻塞,则应使用它,因为默认行为是阻塞。
只需使用普通的read读取可用的任何内容,但仅当您的缓冲区中有packetData.length字节时才将发送数据包以在其他线程中处理...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接