Bytes coming through as -1

A

AndrewTK

I am trying to read binary data from a network input stream but am
having a hard time at it. Consider the following:

public static void main(String[] args) throws Exception {
ServerSocket serversock = new ServerSocket(1234);

while(true) {
try {
Socket s = serversock.accept();
test(s.getInputStream(), s.getOutputStream() );
} catch(Exception e) {
e.printStackTrace();
}
}
}

public static void test(InputStream in, OutputStream out) throws
IOException {
byte[] trash = new byte[10];
int rcount;
while( (rcount = in.read(trash)) != -1) {
for(byte b : trash) {
if(b ==-1) {System.out.print(".");}
}
}
}

So far straightforward. It reads from the input stream and discards the
bytes. It also prints a full stop each time it encounters a byte
/inside the buffer/ that comes through as -1.

In theory, this should never happen: if a byte is -1, it comes out of
the read() method as such, which is normally a flag for read(byte[],
int, int) to stop reading.

However, the above code does print out a full set of dots when I run
the program - I have a form which connects to this server program and
sends a ZIP file to it. Try:

<html><body>
<form action="http://127.0.0.1:1234/" method="POST"
enctype="multipart/form-data">
<input type="file" name="zfile" />
<input type="submit value="send" />
</form></html></body>

When I try to read the ZIP data, expecting -1 at the end of the stream,
reading gets -1 bang in the middle of the data. I am aware that EOS
would occur long after the file data ended, but that's not the point -
I can't even reach the end of the file data.

Any suggestions?

Andrew
 
R

Rogan Dawes

AndrewTK said:
I am trying to read binary data from a network input stream but am
having a hard time at it. Consider the following:
public static void test(InputStream in, OutputStream out) throws
IOException {
byte[] trash = new byte[10];
int rcount;
while( (rcount = in.read(trash)) != -1) {
for(byte b : trash) {
if(b ==-1) {System.out.print(".");}
}
}
}


First problem:

public static void test(InputStream in, OutputStream out) throws
IOException {
byte[] trash = new byte[10];
int rcount;
while( (rcount = in.read(trash)) != -1) {
for(int i=0; i<rcount; i++) {
if(trash ==-1) {
System.out.print(".");
}
}
}
}

You may not necessarily always read complete 10 byte chunks. Always
check how many bytes you actually got from the read, and then only use
that many bytes.

This may solve your problems.

Rogan
 
D

dsjoblom

AndrewTK said:
I am trying to read binary data from a network input stream but am
having a hard time at it. Consider the following:

public static void main(String[] args) throws Exception {
ServerSocket serversock = new ServerSocket(1234);

while(true) {
try {
Socket s = serversock.accept();
test(s.getInputStream(), s.getOutputStream() );
} catch(Exception e) {
e.printStackTrace();
}
}
}

public static void test(InputStream in, OutputStream out) throws
IOException {
byte[] trash = new byte[10];
int rcount;
while( (rcount = in.read(trash)) != -1) {
for(byte b : trash) {
if(b ==-1) {System.out.print(".");}
}
}
}

So far straightforward. It reads from the input stream and discards the
bytes. It also prints a full stop each time it encounters a byte
/inside the buffer/ that comes through as -1.

In theory, this should never happen: if a byte is -1, it comes out of
the read() method as such, which is normally a flag for read(byte[],
int, int) to stop reading.

Note that the read methods return an int, not a byte. Java bytes are
signed, having a range of -128 to 127, so a value of -1 is a perfectly
good value for a byte read from a socket. For more info about
conversions between different types, see
http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1

Regards,
Daniel Sjöblom
 
A

AndrewTK

First problem:
while( (rcount = in.read(trash)) != -1) {
for(int i=0; i<rcount; i++) {
if(trash ==-1) {
System.out.print(".");
}
}

You may not necessarily always read complete 10 byte chunks. Always
check how many bytes you actually got from the read, and then only use
that many bytes.


Thanks for pointing that out Rogan - silly me I should have spotted
that myself.

Unfortunately in my other files I do check for the number of bytes read
(hence the rcount - I was being lazy, I wrote the example specifically
for the post)

Corrected it gives:

public static void test(InputStream in, OutputStream out) throws
IOException {
System.out.println(in.getClass().getName() );
byte[] trash = new byte[10];
int rcount;
while( (rcount = in.read(trash)) != -1) {
for(int i=0;i<rcount;i++) {
if(trash == -1) {System.out.print(".");}
}
}
}



The same output comes back. A load of dots.
 
A

AndrewTK

Note that the read methods return an int, not a byte. Java bytes are
signed, having a range of -128 to 127, so a value of -1 is a perfectly
good value for a byte read from a socket. For more info about
conversions between different types, see
http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1

See Java API for InputStream:
http://java.sun.com/j2se/1.5.0/docs/api/java/io/InputStream.html#read()

"The value byte is returned as an int in the range 0 to 255. If no byte
is available because the end of the stream has been reached, the value
-1 is returned."
 
A

AndrewTK

Which is what I said. It returns an int, not a byte.



It returns an int "in the range of 0 to 255" which does not include -1.

Although thinking of it further I suspect that once stored to the array
it might become signed once more...
 
D

dsjoblom

AndrewTK said:
It returns an int "in the range of 0 to 255" which does not include -1.

Although thinking of it further I suspect that once stored to the array
it might become signed once more...

Yes. If the value is cast to a byte it will become signed if it is
between 128-255. Check out the language spec link I posted earlier.

Regards,
Daniel Sjöblom
 
A

AndrewTK

But you're not calling the read() method! You're calling the
read(byte[]) method! They do different things.

- Oliver

Thanks for pointing that out Oliver.

"The read(b, off, len) method for class InputStream simply calls the
method read() repeatedly."

and

" The read(b) method for class InputStream has the same effect as:

read(b, 0, b.length) "

from the API.

So read() is called and used. If read() returns -1, read(byte[]) and
read(byte[], int, int) both should stop reading.

As previous posts indicate however, reading from the resulting byte
array may not necessarily yeild positive ints.

I pursue search elsewhere I guess.
 
D

dsjoblom

Yes. If the value is cast to a byte it will become signed if it is
between 128-255. Check out the language spec link I posted earlier.

Although, I should add, the block read methods which read into an array
have no need to cast the return value, obviously.

Regards,
Daniel Sjöblom
 
A

AndrewTK

Thanks to all who posted.

I managed to discover and correct the bug. Thanks especially to Daniel
who triggered the thought needed.

My actual program used a custom input stream with an internal buffer.
Its read() method simply returned bytes that were in the buffer,
effectively as /signed/ ints rather than the unsigned int required....!
(I had presumed bytes remained unsigned and that returning ints was the
only way for read() to return -1 in an unsigned world...)

Up until now I had had no problem with the custom buffered stream, but
seen as sevral layers of buffereing were taking place in the new class
I was making/testing, signed ints were proliferating everywhere.

I had
return buffer[offset++];
where I should have had
return buffer[offset++] & 0xFF;
Appending that simple piece of code solved the problem entirely......!

So once again, thanks Daniel for putting me on the track of
signed/unsigned bytes!
 
B

Bill Medland

AndrewTK said:
But you're not calling the read() method! You're calling the
read(byte[]) method! They do different things.

- Oliver

Thanks for pointing that out Oliver.

"The read(b, off, len) method for class InputStream simply calls the
method read() repeatedly."

and

" The read(b) method for class InputStream has the same effect as:

read(b, 0, b.length) "

from the API.

So read() is called and used. If read() returns -1, read(byte[]) and
read(byte[], int, int) both should stop reading.

As previous posts indicate however, reading from the resulting byte
array may not necessarily yeild positive ints.

I pursue search elsewhere I guess.

Perhaps I can clarify; I think I see where you are misunderstanding what is
happening.

(Conceptually) The read() method tries to obtain a byte from the stream (a
value which in Java is between -128 and +127). If it fails to read a byte
it returns the int value of -1. If it succeeds in reading a byte (a value
between -128 and +127) it "converts" it to an int value in the range 0 to
255 and returns that.
The read(byte[]...) methods look at the value returned by read(). If it is
not -1 then it should be a value between 0 and 255. That value is then
"reconverted" back to a byte; a value of -128 to +127 and that byte is
placed in the array. (And so 255 becomes -1 in the array). If the value
returned by read was -1 then that indicates that a byte was not obtained
and so the transfer stops (and that -1 is NOT put into the array). The
read(byte[]...) method returns the number of characters read.
Thus any -1 in the array are values that were successfully read and had all
8 bits set.

If you want to interpret those bytes in the array as unsigned values in the
range 0-255 then you will need to convert them yourself (as read() does).
(However I would question why you would need to convert them like that;
read() does it so that it can return two facts in a single value, similarly
to what the C fgetc function does in returning either EOF or the integer
cast of a char.
 
N

Nigel Wade

AndrewTK said:
I am trying to read binary data from a network input stream but am
having a hard time at it. Consider the following:

public static void main(String[] args) throws Exception {
ServerSocket serversock = new ServerSocket(1234);

while(true) {
try {
Socket s = serversock.accept();
test(s.getInputStream(), s.getOutputStream() );
} catch(Exception e) {
e.printStackTrace();
}
}
}

public static void test(InputStream in, OutputStream out) throws
IOException {
byte[] trash = new byte[10];
int rcount;
while( (rcount = in.read(trash)) != -1) {
for(byte b : trash) {
if(b ==-1) {System.out.print(".");}
}
}
}

So far straightforward. It reads from the input stream and discards the
bytes. It also prints a full stop each time it encounters a byte
/inside the buffer/ that comes through as -1.

In theory, this should never happen: if a byte is -1, it comes out of
the read() method as such, which is normally a flag for read(byte[],
int, int) to stop reading.

However, the above code does print out a full set of dots when I run
the program - I have a form which connects to this server program and
sends a ZIP file to it. Try:

<html><body>
<form action="http://127.0.0.1:1234/" method="POST"
enctype="multipart/form-data">
<input type="file" name="zfile" />
<input type="submit value="send" />
</form></html></body>

When I try to read the ZIP data, expecting -1 at the end of the stream,
reading gets -1 bang in the middle of the data. I am aware that EOS
would occur long after the file data ended, but that's not the point -
I can't even reach the end of the file data.

Any suggestions?

Andrew

I think you are confusing what is read from the stream and the return value of
read(). The read() method returns -1 when it encounters the end of the stream,
this has nothing whatever to do with the bytes which are read. The return value
of read() is either the number of bytes read or -1, not any of the bytes which
was actually read (all of which could be -1).
 
N

Nigel Wade

Nigel said:
AndrewTK said:
I am trying to read binary data from a network input stream but am
having a hard time at it. Consider the following:

public static void main(String[] args) throws Exception {
ServerSocket serversock = new ServerSocket(1234);

while(true) {
try {
Socket s = serversock.accept();
test(s.getInputStream(), s.getOutputStream() );
} catch(Exception e) {
e.printStackTrace();
}
}
}

public static void test(InputStream in, OutputStream out) throws
IOException {
byte[] trash = new byte[10];
int rcount;
while( (rcount = in.read(trash)) != -1) {
for(byte b : trash) {
if(b ==-1) {System.out.print(".");}
}
}
}

So far straightforward. It reads from the input stream and discards the
bytes. It also prints a full stop each time it encounters a byte
/inside the buffer/ that comes through as -1.

In theory, this should never happen: if a byte is -1, it comes out of
the read() method as such, which is normally a flag for read(byte[],
int, int) to stop reading.

However, the above code does print out a full set of dots when I run
the program - I have a form which connects to this server program and
sends a ZIP file to it. Try:

<html><body>
<form action="http://127.0.0.1:1234/" method="POST"
enctype="multipart/form-data">
<input type="file" name="zfile" />
<input type="submit value="send" />
</form></html></body>

When I try to read the ZIP data, expecting -1 at the end of the stream,
reading gets -1 bang in the middle of the data. I am aware that EOS
would occur long after the file data ended, but that's not the point -
I can't even reach the end of the file data.

Any suggestions?

Andrew

I think you are confusing what is read from the stream and the return value of
read(). The read() method returns -1 when it encounters the end of the stream,
this has nothing whatever to do with the bytes which are read. The return value
of read() is either the number of bytes read or -1, not any of the bytes which
was actually read (all of which could be -1).

Ooops, for read() substitute read(byte[]).
 
A

AndrewTK

Ooops, for read() substitute read(byte[]).

As stated in an earlier post:

read(byte[]) and read(byte[], int, int) both use read() which returns
an unsigned integer.

Read() either returns the byte AS unsigned or -1, so read(byte[]) and
read(byte[], int, int) in my head pre-correction should have been
catching these -1 bytes etc etc etc

In a latter post I included (for the benefit of those posting further)
the source of the problem, and where the error lay: in home-grown
buffered readers (which in my case pre-correction were retrning the
legitimate negative bytes as negative, without "casting" them so to
say).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,001
Messages
2,570,254
Members
46,849
Latest member
Fira

Latest Threads

Top