Java InputStream wait for data.

37,789

Solution 1

You can use 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
}

I prefer to use blocking NIO which supports re-usable buffers.

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();
}

Solution 2

As UmNyobe said, available() is meant to be used if you dont want to block as the default behaviour is blocking.

Just use the normal read to read whatever is available but only send packet for processing in other thread once you have packetData.length bytes in your buffer...

Share:
37,789
Bart Platak
Author by

Bart Platak

MEng Computer Systems with Software Engineering student at University of York "Res publica non dominetur"

Updated on July 05, 2022

Comments

  • Bart Platak
    Bart Platak almost 2 years

    I'm developing Server-Client application and I have a problem with waiting for input data on input stream.

    I have thread dedicated to reading input data. Currently it uses while loop to hold until data is available. (N.B. protocol is as follow: send size of packet, say N, as int then send N bytes).

    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
        }
    }
    

    It works but blocking the thread by while loop is IMO a bad idea. I could use Thread.sleep(X) to prevent resources being continously consumed by the loop, but there surely must be a better way.

    Also I can not rely on InputStream.read to block the thread as part of the data may be sent by the server with delays. I have tried but it always resulted in unexpected behaviour.

    I'd appreciate any ideas :)