wood burning stoves 2.0*
The moose likes Sockets and Internet Protocols and the fly likes Socket answer in multiple parts, Client receive only 1 Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Java » Sockets and Internet Protocols
Bookmark "Socket answer in multiple parts, Client receive only 1" Watch "Socket answer in multiple parts, Client receive only 1" New topic
Author

Socket answer in multiple parts, Client receive only 1

Vlad Ator
Greenhorn

Joined: Nov 05, 2003
Posts: 10
Hi All,
I have to send a String to a server and this server will then reply me with another String. The String's are valid xml, but it doesn't really matter. I need to use Sockets to do that. The answer is quite long, like 2000 characters.
Most of the time, everything is working fine. But sometimes (maybe 1%), i only receive in my code a part of the answer, not the full one. I used a Tunnel program to see what the server sends to me, and it seems that it send the full answer. I guess that this answer is sent into multiple parts, and my client doesn't wait enough time to get the last part. Is it possible ? This is my code :
bufferedOutputStream.write(xmlString.getBytes());
bufferedOutputStream.flush();
CharArrayWriter charArrayWriter = new CharArrayWriter();
c=bufferedInputStream.read();
while(bufferedInputStream.available() > 0)
{
charArrayWriter.write(c);
c=bufferedInputStream.read();
}
charArrayWriter.write(c);
result = charArrayWriter.toString();
Detlev Beutner
Ranch Hand

Joined: Jul 13, 2001
Posts: 76
Hello Vlad,
the problem is the use of the method "available" (please, read the apidoc). This returns 0, when there is no byte to be read *without blocking*. So it is possible that the underlying InputStream is not empty, but the BufferedInputStream is "empty so far" (waiting for the next bytes).
So, please check the read-method if it is returning -1 (now the end of the stream has been reached).
Hope it helps
Detlev
Vlad Ator
Greenhorn

Joined: Nov 05, 2003
Posts: 10
Hi,
Thanks for your answer.
I updated my code like that, but now it's blocked waiting for someting...

c=bufferedInputStream.read();

//while(bufferedInputStream.available() > 0)
while(c != -1)
{
charArrayWriter.write(c);
c=bufferedInputStream.read();
}
charArrayWriter.write(c);
What can i do ?
Detlev Beutner
Ranch Hand

Joined: Jul 13, 2001
Posts: 76
Hello Vlad,
I don't know how the blocking now arises. At least, you could make your code more nice; probably this will not effect the problem, but first it could make it easier to understand the problem while debugging, second it could be nice for you to learn better style:
You will have noticed that you have twice a similar line with read() and twice a similar line with write(c). This should be enough reason to clean up the code. So, how to do this? Ask yourself: What *has* to be done (answer: the program will have to read() at least once). This results in the fragment

(Look at the spaces beneath "="... Java Coding Conventions...)
Ok, how many times has this to be done? As long as the return value is not equal -1. And what has to be done with the return value? It should be written to your charArrayWriter. BUT! Not in the case when it is -1 (this is an error in your code)! Leads directly to:

Hope it helps
Detlev
Vlad Ator
Greenhorn

Joined: Nov 05, 2003
Posts: 10
Hi,
Thanks again for the answer. About the structure of the code, you're off course right, it was already updated. But i made a lot of changes/tests to try to succeed, and this ugly code was the last one...
It still doesn't work, but i have a question about BufferedInputStream and its method "available". The description is
"Returns the number of bytes that can be read from this input stream without blocking". I can't find anywhere an explanation of which cases can block (bad character, stream never ended, then why ?, ...)
Could someone explain ?
Thanks a lot !
Vlad
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
When available() returns 0 all it means is that there aren't any bytes available right now. That might be because there's a tiny delay in the network and more bytes will be available within milliseconds - or it might mean that no bytes are available yet because they haven't been sent from the other end of the stream yet. Maybe we're waiting for a user to press a button or something. Or maybe there's some sort of networking error and the stream has gotten somhow disconnected from the source (but hasn't thrown an error yet sinc ethe problem hasn't been detected.) Ultimately, the available() method is pretty useless for figureing out what's wrong.
I would suggest that if your method is still blocking with the latest code shown above, you should look at what's happening at the other end of the socket. Has the server sent all the information it needs to? Is the socket still open? Quite possibly, the server has sent a complete message, but the socket is still open because the server is still listening for input from you. If you send another signal to the server, the server will respond again using the same socket. So in between messages, your program is blocking because it's listening to the server, and the server doesn't have anything else to say.
I'd recommend printing out everything that you receive from the socket, as it arrives, so you can figure out where in the message you are. You may find that you need to put the socket reader in a separate thread so that it keeps listening to the server, but your program can do other things while it's waiting.
Indicentally, your socket reading can be made much more efficient if you read bytes in bulk rather than one at a time. Also, if you're converting bytes to chars you'd be better off using an InputStreamReader so you can control character encoding easily.

If the server responds in test messages, and if it always ends messsages with a newline, then you might also benefit from a BufferedReader:


"I'm not back." - Bill Harding, Twister
Detlev Beutner
Ranch Hand

Joined: Jul 13, 2001
Posts: 76
Hello Jim,
I also prefer to control the buffer by myself, but indeed it does not (or seldom) matter if you prefer to buffer the input by yourself or if you decide to take a BufferedInputStream. It "looks" faster if you have your own buffer (in the code, you "see" catching some thousand bytes at one time), but if you read from a BufferedInputStream, it has done the same before and catching the bytes works in memory, so the result normally is the same.
Just for clarification,
hope it helps
Detlev
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
It's true I shouldn't have said the bulk read is much more efficient, as in many cases the difference will be negligible. In particular, if there's some other part of the process that's particularly slow, such as reading or writing to a disk or socket, then the relative overhead of JVM method calls is probably negligible. But some types of streams are relatively quick - e.g. ByteArrayOutputStream or StringWriter - and just on general principle I hate to call read() thousands of times when a single read(byte[]) will do. If you're dealing with a fast stream, then the overhead of individual method calls can be significant. Also, if you've got a BufferedInputStream and a BufferedOutputstream, you're spending a certain amount of time transferring data from one buffer to another. Whereas by providing the buffer yourself, you can use the same buffer for input and output, and eliminate that unnecessary copying.
Basically, I figure it's just good practice to use bulk operations when they're available. Maybe 80% of the time it doesn't really matter, but there's no penalty for using them, and they come in handy the remaining 20% of the time.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Socket answer in multiple parts, Client receive only 1
 
Similar Threads
sending string using writeUTF
How can final and transient be used in a variable declaraion?
communciate with c server
chararraywriter
How to get selected radioButton?