Artyom
Artyom

Reputation: 1599

Accurately detecting socket sending failures in Java

I am writing an Android app that initializes a DatagramSocket to connect to a server and then uses an infinite loop to periodically (e.g. every 5 seconds) send packets of data. The sending code is below:

DatagramPacket packet = new DatagramPacket(message, message.length);
try {
    socket.send(packet);
}
catch (IOException e) {
    // Log failure and return
}
// Log success

Now, I can afford to lose a packet every once in a while. But I would like to be able to detect if the server becomes unavailable (e.g. crashes) while I am connected, in which case I would like to hold on to the messages I send (to send them at another time). Originally I thought that an exception will be thrown every time I try to send a packet through this socket, and hence would be able to deal with storing the messages in my catch block. In fact it partially works. I model server crashes by just switching off the server, and I start getting exceptions with message sendto failed: ECONNREFUSED (Connection refused) when I send a packet. The problem is, not every attempt to send throws an exception, but only every even attempt - so my log looks like

Success, Error, Success, Error, ...

What happens in my understanding is that on the first attempt to send a packet after the server becomes unavailable, the packet gets sent, the socket doesn't wait to see if there is an error message, and a success is logged. Then on the next attempt, the socket tries to send a packet, sees the previous error message, and throws an exception without sending the packet, hence leading to an error being logged. However, because the packet was not sent, there will be again no exception thrown on the subsequent attempt to send a packet. This is a hypothesis I drew after seeing my log, so I could be mistaken in my reasoning here.

My question is, is there any way to make sure the exception is thrown every time as long as the server is unavailable? Or is there any other way to detect that the other end of the socket has silently disconnected? I tried checking for socket.isConnected() inside my loop, but it always returns true.

Upvotes: 0

Views: 1570

Answers (1)

Gray
Gray

Reputation: 116878

DatagramSocket are by definition connection-less -- here's a good page about the differences between UDP and TCP for posterity. That you are getting any errors at all indicates to me that you are sending to a server on your local network which is not responding to arps -- either that our your default gateway is going away which is less likely. That any of your send messages are returning errors is very OS and network dependent and IMO should not be relied upon. It also means that if you put a router between you and the server then none of the send methods would return error I believe.

If you need to see if the server is up and has received your messages then I would recommend that you add code to the server to send an acknowledgement back to the client. You wouldn't want the client to send and wait for the ack for each packet but maybe send X packets and then wait for the ack for all X or have a wait table with a retransmit thread or something.

Of course, once you start down that road, you may want to consider using Jgroups or switching to TCP/IP. :-)

Upvotes: 3

Related Questions