Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java InputStream wait for data.

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 :)

like image 486
Bart Platak Avatar asked Mar 12 '12 12:03

Bart Platak


2 Answers

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

like image 97
Filipe Pina Avatar answered Oct 19 '22 09:10

Filipe Pina


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();
}
like image 14
Peter Lawrey Avatar answered Oct 19 '22 10:10

Peter Lawrey