Java InputStream等待数据.

Bar*_*tak 10 java sockets stream

我正在开发Server-Client应用程序,我在输入流上等待输入数据时遇到问题.

我有致力于读取输入数据的线程.目前,它使用while循环来保持数据可用.(NB协议如下:发送数据包的大小,比如N,作为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
    }
}
Run Code Online (Sandbox Code Playgroud)

它的工作原理但是通过while循环阻塞线程是IMO的一个坏主意.我可以使用Thread.sleep(X)来防止循环继续消耗资源,但肯定必须有更好的方法.

此外,我不能依赖InputStream.read来阻止线程,因为数据的一部分可能由服务器发送延迟.我试过但它总是导致意想不到的行为.

我很感激任何想法:)

Pet*_*rey 13

您可以使用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
}
Run Code Online (Sandbox Code Playgroud)

我更喜欢使用支持可重用缓冲区的阻塞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();
}
Run Code Online (Sandbox Code Playgroud)

  • 您可能不希望将2GiB读入您的记忆中 (3认同)

Fil*_*ina 5

作为UmNyobe说,available()是为了使用,如果你希望阻止的默认行为是阻塞。

只需使用常规read读取任何可用的内容,但仅在缓冲区中有字节后才发送数据包以供其他线程处理packetData.length ...