Walter Bianchi
Walter Bianchi

Reputation: 79

Java stream of byte. Read operation sometimes doesn't read what was written

I'm trying to implement a communication system with an automatic repeat request strategy. I use three classes: Transmitter, Channel, Receiver. I have a maximum number of byte for message (window). But when I receive the byte sent, sometimes I receive less bytes than window. Why? My code is this:

Transmitter

int n = 0;
int remaining, length;
while (n<channelBytes.length) {
     remaining = channelBytes.length-n;
     length = (remaining<window)? remaining : window;
     outputStream.write(channelBytes,n,length);
     // wait for the ack
     byte[] b = new byte[4];
     channel.socket().setSoTimeout(2000);
     inputStream.read(b);
     n += ByteBuffer.wrap(b).getInt();
}

Channel

bytes = new byte[SystemModel.WINDOW];
while(true) {
    // receive from Tx
    upInputStream.read(bytes);
    // insert channel error
    insertError(bytes);
    Thread.sleep(propagationDelay + transmissionDelay);
    // send bytes to Rx
    downOutputStream.write(bytes);
    // wait for the ack from Rx
    clientChannelDown.socket().setSoTimeout(2000);
    byte[] ack = new byte[4];
    downInputStream.read(ack);
    // send ack to Tx
    upOutputStream.write(ByteBuffer.allocate(4).put(ack).array());
}

Receiver

byte[] b = new byte[SystemModel.WINDOW];
while (true) {
    try {
        int received = inputStream.read(b);
        channelCoding.decodePartially(b);                                        
    }catch (SocketTimeoutException te){  
        break;
    } catch (IOException e) {
        e.printStackTrace();
    } catch (DataFormatException e) {
        // send ack
        int ack = Integer.parseInt(e.getMessage());
        try {
            outputStream.write(ByteBuffer.allocate(4).putInt(ack).array());
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
}

In the Receiver, the array of bytes "b" is not always the length of the window.

Upvotes: 0

Views: 178

Answers (1)

user207421
user207421

Reputation: 310885

Invalid code. See the Javadoc. InputStream.read(byte[] [,...]) isn't obliged to transfer more than one byte, and it is never valid to call it without storing the result into a variable. If you're expecting more than one byte, you have to loop, or use DataInputStream.readFully().

The canonical way to copy streams in Java is as follows:

while ((count = in.read(buffer)) > 0)
{
    out.write(buffer, 0, count);
}

For ByteBuffers with Channels it is as follows:

while (in.read(buffer) > 0 || buffer.position() > 0)
{
    buffer.flip();
    out.write(buffer);
    buffer.compact();
}

If you code correctly there is no need to insert sleeps into network code.

E&OE

Upvotes: 1

Related Questions