Android - Socket time out - java

I have some strange socket behavior going on. I've set an timeout of 5 seconds using setSoTimeout. This should be plenty of time in my situation. According to online java documentation a SocketTimeoutException should be thrown if it times out. It also says that the socket is still valid. So I want to catch it and then continue. However instead of the inner catch, the outer catch IOException is catching the expception and when I output to the log the details it says it was a SocketTimeoutException. Another perplexing thing is I change the timeout from 5 seconds to say, 15 seconds and log the amount of time it take for every read, the times are always in the milli-second range, never even close to a second. Any ideas are GREATLY appreciated.
ReadThread code snippet
#Override
public void run()
{
try
{
while (true)
{
byte[] sizeBuffer = new byte[BYTES_FOR_MESSAGE_SIZE];
int bytesRead = this.inputStream.read(sizeBuffer);
int length = 0;
for (int i = 0; i < BYTES_FOR_MESSAGE_SIZE; i++)
{
int bitsToShift = 8 * i;
int current = ((sizeBuffer[i] & 0xff) << bitsToShift);
length = length | current;
}
byte[] messageBuffer = new byte[length];
this.socket.setSoTimeout(5000); //5 second timeout
try
{
this.inputStream.read(messageBuffer);
}
catch(java.net.SocketTimeoutException ste)
{
Log.e(this.toString(), "---- SocketTimeoutException caught ----");
Log.e(this.toString(), ste.toString());
}
}
}
catch (IOException ioe)
{
Log.e(this.toString(), "IOException caught in ReadThread");
Log.e(this.toString(), ioe.toString());
ioe.printStackTrace();
}
catch (Exception e)
{
Log.e(this.toString(), "Exception caught in ReadThread");
Log.e(this.toString(), e.toString());
e.printStackTrace();
}
this.interfaceSocket.socketClosed();
}// end run

I agree with Brian. You are probably getting the timeout on the first read, not the second. The timeout once set remains in effect until you change it again.
Your second read call where you read the 'message' seems to assume (a) that it will read the entire message and (b) that it will timeout if the entire message doesn't arrive within 5s. It doesn't work like that. It will timeout if nothing arrives within 5s, or else it will read whatever has arrived, up to message.length. But it could only be one byte.
You should use DataInputStream.readFully() to read the entire message, and you need to completely reconsider your timeout strategy.

The exception is probably caught in the first try catch because of the earlier call to this.inputStream.read(). You have two of these calls: one in the outer try, one in the inner try.
Have you validated if data is being read? If data is being read then you should expect the read operation to return after a few milliseconds. If data is not being read, then the read operation should block there for the time you specify. Maybe this has to do with the order by which you setSoTimeout (perhaps doing it earlier will help).
Good luck,
B-Rad

Related

Java Socket doesn't unblock even with read timeout

I have an application to write the request data over socket and read the response.
Some times Host doesn't respond to request and my code blocks, even though I'm using a read timeout.
There is no way to clear it manually and it require system to be rebooted or restart on the server handler required.
Here is the code used. Connection appears to block at objBufferedInputStream.read(..)
Socket clientSocket = new Socket(objInetAddress, hostPort);
clientSocket.setKeepAlive(true);
clientSocket.setReceiveBufferSize(8192);
clientSocket.setSendBufferSize(8192);
clientSocket.setSoTimeout(waitTimeBeforeSocketClose * 1000);
objBufferedInputStream = new BufferedInputStream(clientSocket
.getInputStream());
.......
objBufferedOutputStream.write(message, 0, message.length);
objBufferedOutputStream.flush();
while (bytesLeft > 0 && bytesread > -1) {
try {
bytesread = objBufferedInputStream.read(data, 4096 - bytesLeft, 1);
} catch (IOException e) {
objLogger.writeException(e);
try {
objBufferedInputStream.close();
} catch (IOException e1) {
objLogger.writeException(e1);
return null;
}
return null;
}
bytesLeft -= bytesread;
}
return data;
}
Please advise whether this is expected behavior when the host doesn't respond or hold the response.
Please advise whether there is alternate approach.
Either:
waitTimeBeforeSocketClose is zero, so you are blocking indefinitely, or
It is non-zero, so you're getting a SocketTimeoutException inside your loop, and ignoring it, so you spin forever. Add a separate catch block for SocketTimeoutException with a break; inside it. Never just ignore an IOException. In this case I would say you should exit the loop on any IOException, so you could also consider putting the try/catch outside the loop.
Reading one byte at a time is pretty poor. I don't see the point of that.

Synchronizing data output stream

I'm having a problem where I have a class that gets instantiated upon a connection to server.
The method I'm having trouble with in the class looks like so:
public void sendData(byte[] dataToSend) throws IOException {
sendLock.lock();
int dataLength = dataToSend.length;
dout.writeInt(dataLength);
dout.write(dataToSend, 0, dataLength);
dout.flush();
sendLock.unlock();
}
Where sendLock is a ReentrantLock and dout = new DataOutputStream(socket.getOutputStream());. This will work fine with a limited number of threads, but if I have a large number of threads calling this method concurrently I get a deadlock and the program just stops.
Is there any reason a deadlock would be happening here? It doesn't make sense to me, as I've removed all other locks to rule them out and I'm down to this one. Is there anyway the flush could cause things to hang or something? It just seems like at some point it never releases the lock and I'm not sure why.
If I remove the lock I get socket errors because one thread may change the dataLength before another has a chance to write, etc. But the deadlock no longer occurs.
As a reference, here's what the run method of the Receive end looks like:
public void run() {
while (socket != null) {
try {
int dataLength = din.readInt();
byte[] data = new byte[dataLength];
din.readFully(data, 0, dataLength);
Event e = ef.getEvent(data);
node.onEvent(e);
} catch (SocketException se) {
System.out.println(se.getMessage());
break;
} catch (IOException ioe) {
System.out.println(ioe.getMessage()) ;
break;
}
}
}
It's possible that one of your calls to the output stream throws an exception and sendLock.unlock() is never called. All the other threads will be left waiting forever.
Check your logs to see if one of the threads throws an exception. In your code I would use a try-catch-finally block instead of throwing IOException. This guarantees, even if something bad happens, the lock will be released so other threads can keep working.
public void sendData(byte[] dataToSend) throws IOException {
try {
sendLock.lock();
int dataLength = dataToSend.length;
dout.writeInt(dataLength);
dout.write(dataToSend, 0, dataLength);
dout.flush();
}
finally {
sendLock.unlock();
}
}

Can't detect disconnect without extra readLine() loop

I am developing a program that uses sockets and currently I have a function in my code that checks for a heartbeat from the client every second.
private void userLoop() { // checks for incoming data from client
Timer t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
try {
socketIn.read(); // check for heartbeat from client
String userInput;
while ((userInput = br.readLine()) != null) {
}
} catch (Exception e) {
ControlPanel.model.removeElement(getUsername());
ControlPanel.append(getUsername() + " has disconnected.");
}
}
}, 1000);
}
When a client closes the game via the X button, shutting off their computer, logging out, whatever it may be, I get the message "'username' has disconnected". This is exactly what I want, however, it only works with the while loop in the code. The while loop essentially does nothing and I have no idea why it doesn't work with out.
If I remove the while loop and I disconnect using my client nothing gets printed out server sided.
String userInput;
while ((userInput = br.readLine()) != null) {
}
The above is essentially the dead code that does nothing but without it my program doesn't work the way it should..
Why is the code needed and how can I remove it and still make my program work correctly?
In this case, your while loop is essentially stalling your program until you no longer receive an input string. It's not dead code; it is just your way of installing a wait.
Otherwise, based on my understanding in the Timer class, it only waits one second, which might be too short of a timespan for what you're waiting to capture.
I fixed my problem by changing everything in the try block with
br.readLine();
There's a saying I've heard about exception handling: "Exceptions should only be used for exceptional situations." A client disconnecting from a server is not exceptional.
Now that I have that off my chest, let's move on. According to this other question,
socket.getInputSteam.read() does not throw when I close the socket from the client
it sounds like the read call won't throw if you're closing things properly on the client side.
The problem is that when the remote socket is closed, read() does not throw an Exception, it just returns -1 to signal the end of the stream.
The following should work without needing to call readLine():
try {
int ret = socketIn.read(); // check for heartbeat from client
if (ret == -1) {
// Remote side closed gracefully
clientDisconnected();
}
} catch (SocketTimeoutException e) {
// Timeout -- handle as required
handleTimeout();
} catch (IOException e) {
// Connection lost due to I/O error
clientDisconnected()
}

EOFException - how to handle?

I'm a beginner java programmer following the java tutorials.
I am using a simple Java Program from the Java tutorials's Data Streams Page, and at runtime, it keeps on showing EOFException. I was wondering if this was normal, as the reader has to come to the end of the file eventually.
import java.io.*;
public class DataStreams {
static final String dataFile = "F://Java//DataStreams//invoicedata.txt";
static final double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 };
static final int[] units = { 12, 8, 13, 29, 50 };
static final String[] descs = {
"Java T-shirt",
"Java Mug",
"Duke Juggling Dolls",
"Java Pin",
"Java Key Chain"
};
public static void main(String args[]) {
try {
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dataFile)));
for (int i = 0; i < prices.length; i ++) {
out.writeDouble(prices[i]);
out.writeInt(units[i]);
out.writeUTF(descs[i]);
}
out.close();
} catch(IOException e){
e.printStackTrace(); // used to be System.err.println();
}
double price;
int unit;
String desc;
double total = 0.0;
try {
DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(dataFile)));
while (true) {
price = in.readDouble();
unit = in.readInt();
desc = in.readUTF();
System.out.format("You ordered %d" + " units of %s at $%.2f%n",
unit, desc, price);
total += unit * price;
}
} catch(IOException e) {
e.printStackTrace();
}
System.out.format("Your total is %f.%n" , total);
}
}
It compiles fine, but the output is:
You ordered 12 units of Java T-shirt at $19.99
You ordered 8 units of Java Mug at $9.99
You ordered 13 units of Duke Juggling Dolls at $15.99
You ordered 29 units of Java Pin at $3.99
You ordered 50 units of Java Key Chain at $4.99
java.io.EOFException
at java.io.DataInputStream.readFully(Unknown Source)
at java.io.DataInputStream.readLong(Unknown Source)
at java.io.DataInputStream.readDouble(Unknown Source)
at DataStreams.main(DataStreams.java:39)
Your total is 892.880000.
From the Java tutorials's Data Streams Page, it says:
Notice that DataStreams detects an end-of-file condition by catching EOFException, instead of testing for an invalid return value. All implementations of DataInput methods use EOFException instead of return values.
So, does this mean that catching EOFException is normal, so just catching it and not handling it is fine, meaning that the end of file is reached?
If it means I should handle it, please advise me on how to do it.
EDIT
From the suggestions, I've fixed it by using in.available() > 0 for the while loop condition.
Or, I could do nothing to handle the exception, because it's fine.
While reading from the file, your are not terminating your loop. So its read all the values and correctly throws EOFException on the next iteration of the read at line below:
price = in.readDouble();
If you read the documentation, it says:
Throws:
EOFException - if this input stream reaches the end before reading eight bytes.
IOException - the stream has been closed and the contained input stream does not support reading after close, or another I/O error occurs.
Put a proper termination condition in your while loop to resolve the issue e.g. below:
while(in.available() > 0) <--- if there are still bytes to read
The best way to handle this would be to terminate your infinite loop with a proper condition.
But since you asked for the exception handling:
Try to use two catches. Your EOFException is expected, so there seems to be no problem when it occures. Any other exception should be handled.
...
} catch (EOFException e) {
// ... this is fine
} catch(IOException e) {
// handle exception which is not expected
e.printStackTrace();
}
You can use while(in.available() != 0) instead of while(true).
Alternatively, you could write out the number of elements first (as a header) using:
out.writeInt(prices.length);
When you read the file, you first read the header (element count):
int elementCount = in.readInt();
for (int i = 0; i < elementCount; i++) {
// read elements
}
You may come across code that reads from an InputStream and uses the snippet
while(in.available()>0) to check for the end of the stream, rather than checking for an
EOFException (end of the file).
The problem with this technique, and the Javadoc does echo this, is that it only tells you the number of blocks that can be read without blocking the next caller. In other words, it can return 0 even if there are more bytes to be read. Therefore, the InputStream available() method should never be used to check for the end of the stream.
You must use while (true) and
catch(EOFException e) {
//This isn't problem
} catch (Other e) {
//This is problem
}
You catch IOException which also catches EOFException, because it is inherited. If you look at the example from the tutorial they underlined that you should catch EOFException - and this is what they do. To solve you problem catch EOFException before IOException:
try
{
//...
}
catch(EOFException e) {
//eof - no error in this case
}
catch(IOException e) {
//something went wrong
e.printStackTrace();
}
Beside that I don't like data flow control using exceptions - it is not the intended use of exceptions and thus (in my opinion) really bad style.
Put your code inside the try catch block:
i.e :
try{
if(in.available()!=0){
// ------
}
}catch(EOFException eof){
//
}catch(Exception e){
//
}
}
EOFException being a child of IOException
I prefer it like below ==>
try {
.
.
.
} catch (IOException e) {
if (!(e instanceof EOFException)) {
throw new RuntimeException(e);
}
}

Problems with InputStream

Following is a part of the code snippet that I will be using for my project.
public String fetchFromStream()
{
try
{
int charVal;
StringBuffer sb = new StringBuffer();
while((charVal = inputStream.read()) > 0) {
sb.append((char)charVal);
}
return sb.toString();
} catch (Exception e)
{
m_log.error("readUntil(..) : " + e.getMessage());
return null;
} finally {
System.out.println("<<<<<<<<<<<<<<<<<<<<<< Called >>>>>>>>>>>>>>>>>>>>>>>>>>>");
}
}
Initially the while loop start working pretty fine. But after the probable last character is read from the stream I was expecting to get -1 return value. But this is where my problem starts. The code gets hanged, even the finally block is not executed.
I was debugging this code in Eclipse to see what is actually happening during the run-time. I set a pointer (debug) inside the while loop and was constantly monitoring the StringBuffer getting populated with char values one by one. But suddenly while checking the condition inside the while loop, the debugging control is getting lost and this is the point where the code goes to hangup state !! No exception is thrown as well !!
What is happening here ?
Edit::
This is how I'm getting my InputStream. Basically I'm using Apache Commons Net for Telnet.
private TelnetClient getTelnetSession(String hostname, int port)
{
TelnetClient tc = new TelnetClient();
try
{
tc.connect(hostname, port != 0 ? port : 23);
//These are instance variables
inputStream = tc.getInputStream();
outputStream = new PrintStream(tc.getOutputStream());
//More codes...
return tc;
} catch (SocketException se)
{
m_log.error("getTelnetSession(..) : " + se.getMessage());
return null;
} catch (IOException ioe)
{
m_log.error("getTelnetSession(..) : " + ioe.getMessage());
return null;
} catch (Exception e)
{
m_log.error("getTelnetSession(..) : " + e.getMessage());
return null;
}
}
Look at the JavaDocs:
Reads the next byte of data from the input stream. 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. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.
In simple turns: if your stream ended (e.g. end of file), read() returns -1 immediately. However if the stream is still open but JVM is waiting for data (slow disk, socket connection), read() will block (not really hung).
Where are you getting the stream from? Check out the available() - but please do not call it in a loop exhausting CPU.
Finally: casting int/byte to char will only work for ASCII characters, consider using Reader on top of InputStream.
read the docs
read() will wait until there is more data on the InputStream if the InputStream is not closed.
I suspect you are doing this with sockets? This is the most common area where this comes up.
"Reads the next byte of data from the input stream. 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. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown"
I have the same issue with the Apache Commons on Android ...
the read() command on the inputstream hangs forever for some reason. And no, it is not just blocking "until data is available" ...
my debugging information shows that there are several 100 chars available() ... yet it just randomly blocks at some read. However, whenever I send something to the telnet server the block is suddenly released and it will continue reading for several chars until it suddenly stops/blocks again at some arbitrary point!
I believe there is some bug within the Apache Commons library! This is really annoying because there isn't a lot that can be done ... no timeout for the read command or anything else ...
EDIT: I was able to get around it ... by setting the TelNetClient.setReaderThread(false) ... obviously there is a bug within the Library that exists as long as a thread handles the input data ... when dispabled it works just fine for me!

Categories