We are integrating with an external product that requires us to communicate with it using Java sockets. We’ve been able to read small responses from the server with no issues, but larger responses are causing some headaches.
I made some changes to the socket handling logic and now we seem to be able to read large responses 90% of the time. It does still fail occasionally. Failure, in this case, means that the Java client stops reading from the socket before the entire response has been read. The client thinks that the read operation is finished, and stops normally – there are no exceptions or timeouts involved.
Here’s what the current logic looks like:
StringWriter response = new StringWriter();
PrintWriter writer = new PrintWriter(response);
char[] buf = new char[4096];
int readChars;
do {
readChars = responseBufferedReader.read(buf);
writer.write(buf, 0, readChars);
} while(readChars != -1 && responseBufferedReader.ready());
responseBufferedReader is a BufferedReader wrapped around an InputStreamReader wrapped around the Socket‘s InputStream.
This code works most of the time, but it seems like checking for readChars != -1 and ready() are not reliable enough to indicate if we’ve read all of the content from the server. Comparing the number of read characters to the buffer size is also not reliable, since the server seems to be a little slow at sending the response back causing these numbers to differ.
I’ve tried changing the size of the character buffer; it helped, but it’s still not working 100% of the time.
Is there a better and more reliable way to read entirely from a Socket without knowing the size of the expected response? I’ve been doing some research on SocketChannels, but I’m not sure if there’s any benefit to be had by switching.
In case it helps, we’re making a single, blocking Socket connection to the server. The Socket is configured for a 100 second timeout
You shouldn’t be checking whether the BufferedReader is ready() to tell if you’re done. It’s possible that bytes are still being read off of the wire and the BufferedReader has nothing for you, but the Socket is not yet closed.
I’m not sure what value the BufferedReader is getting you (well, it might help your performance). I would expect the following to work better:
I think that you’re probably dropping out of the loop when the network is the bottleneck – the loop processes the results fast enough so that the Reader isn’t ready yet and you assume that you’re done reading (even though you’re not).