Win a copy of Kotlin in Action this week in the Kotlin forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

BufferedReader conflicting with InputStream ?  RSS feed

 
Vincent Verdot
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello all,
I am writing a program composed of a server and a client (see code below). The client must send data (byte[]) to the server.. To achieve this, it sends a name (identifying the data), a size (also as String), and finally the data.
On client side I create a socket and write the name/size via a PrintWriter and the raw data directly via a OutputStream.
On server side, I read the name and the size via a BufferedReader and then the raw data via the InputStream.

The problem is that when reading the data, input.read() always returns -1 (end of stream I guess). (of course, name and size are correctly transmitted).

I printed some debug information (input.available()) and the InputStream seems to have all its data consumed by the BufferedReader.

I already found another way to achieve the transfer succesfully (e.g. by using only BufferedReader) but I don't find the method convenient and I don't understand why I cannot use InputStream and BufferedReader. Actually I am looking for an explanation.

Last but not least, I am using this code (client and server) in another part of my program (exactly the same code) and guess what ? It works perfectly . The only difference I found is that my problem occurs when the client and the server are on the same machine (IPC purpose). In other words, the same code works correctly when client and server are on different machines. (Maybe the BufferedReader reads more data in local conditions?).

Any idea? Thank you in advance.



 
Ernest Friedman-Hill
author and iconoclast
Sheriff
Posts: 24217
38
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,

Welcome to JavaRanch!

A BufferedReader "buffers" the input it reads; hence the name.

Reading a single byte from a file or from the network is an expensive operation. Reading two bytes at a time, or a hundred, takes barely any more time. It's the act of reading from those slow media that takes time. So you want to avoid making more calls to InputStream.read() than you need to.

"Buffering" means reading more than is requested, so that when later read requests come in, the BufferedReader can hand out data it previously read without going back to the InputStream again. Reading data from the BufferedReader's internal "buffer" is cheap.

Because the BufferedReader reads more than you ask for, once you connect a BufferedReader to a stream, you should never read directly from that stream again.
 
Vincent Verdot
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Ernest Friedman-Hill:
you should never read directly from that stream again.


That's ok, so in my case how could I get bytes from the BufferedReader?
 
Vincent Verdot
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Here my solution (if it can help).
The client side is almost the same, except that I no more use PrintWriter.println(). Instead I print the String and concatenate '\n', thus I don't have to handle "\r\n" on server side.

BTW, I am still wondering why can I use an InputStream and a BufferedReader from a same stream in some situations (e.g. when client and server are on different hosts).

Here, I use a BufferedInputStream for efficiency (compared to InputStream) but I have to parse each String manually. I think this solution is suitable if the mainly transmitted information is raw data.



 
Ernest Friedman-Hill
author and iconoclast
Sheriff
Posts: 24217
38
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
One convenient way would be to use DataInputStream on one end, and DataOutputStream on the other, instead of BufferedReader and PrintWriter. Then use the readUTF() and writeUTF() methods to exchange the string ID, and the read() and write() methods just as you're doing now (except on the DataInput/OutputStreams, not the raw network streams.) You can use the DataInputStream in conjunction with a BufferedInputStream to provide the buffering, if you want -- although here I think all you really wanted was the readLine() method anyway, right?
 
Vincent Verdot
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Ernest Friedman-Hill:
although here I think all you really wanted was the readLine() method anyway, right?


Yes, it's true . Anyway, I am rather satisfied of my second solution (don't know if you saw it -- cross-posted ? --). I don't know if it is efficient but it works fine.
You helped me when you told that I cannot (at least I should not) use a InputStream and a BufferedReader (applied to the same input) concurrently. I wasn't sure about that because I didn't find any information in javadocs and other forums.. Thanks.
 
Consider Paul's rocket mass heater.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!