3

Is there a way to get some details regarding exception safety aspects of Java's standard classes? Mainly working with C++ and C#, I'm confused with Java exception specifications, so I need to understand the proper way of working with exceptions.

To be more specific, let's consider ServerSocket. It starts listening for incoming connections as soon as its object is constructed. Then, you should use accept() to accept the connection (if someone tries to connect).

In case you've previously configured your server socket with setSoTimeout(), there's a change that accept() will throw SocketTimeoutException because nobody tried to connect in a specified period of time. That's fine, server socket is still usable, so you just call accept() once again.

But SocketTimeoutException is not the only thing that accept() may throw. What does all the other exceptions mean? If I wrap call to accept() with 2 catch clauses: for SocketTimeoutException and IOException, can I still safely use the related ServerSocket instance after I got into IOException clause?

I'd really appreciate both Java-wide and ServerSocket-specific answers.

Raedwald
  • 46,613
  • 43
  • 151
  • 237
Andrey Agibalov
  • 7,624
  • 8
  • 66
  • 111
  • 1
    you'd have to dig into the javadocs to see what all of the other exceptions mean. something well documented would explain what's going on. Java-wide, there's no answer. The object still exists after the exception occurs, but what *state* that object is in depends on the implementation of that specific thing. – John Gardner Aug 12 '11 at 23:33
  • @John Gardner: have already spent too much time reading docs. No explicit answers. What does the "I/O error occurred" stand for? Does it mean my LAN card's dead or is it just a network lag for a couple of seconds? While the first one is critical, the second one is not so obvious to be "unrecoverable". – Andrey Agibalov Aug 12 '11 at 23:44

6 Answers6

3

It is not safe to reuse the object. For such a question I would always look into a source, that is the reason it is open.

So if you look into that one: http://kickjava.com/src/java/net/ServerSocket.java.htm you notice that in accept() a SocketException (inherits from IOException) is thrown if the socket is closed or not bound anymore. Both states indicate that the ServerSocket is not valid anymore.

So for this class, generally, if you fail with an exception, always try to gracefully close the ServerSocket in a finally block and then recreate it.

Additionally on your Java-wide question scope: Always look into the source and understand what the interface is doing. If it is mission-critical write tests that reproduce the behaviour (should not be easy at all with such a low-level api).

Finally - is Java consistently doing such things that way? No. Some classes are stateless, others are not (like ServerSocket), some are thread-safe, others not. And you need to understand - either from the documentation or (mostly) from the code - what state they build in order to understand what to do when an Exception knocks you off from the main path.

Most people curse those checked Java exceptions, because most of them (as with most of the IOExceptions) are not really recoverable in a meaningful way. Most of the time, they argue, you cannot understand each and every fine corner case. Which is the reason why many complex frameworks may retry twice or thrice if they think in this case they might, but finally throw a RuntimeException to a top framework layer. There they make something useful out of it (a meaningful error providing context) and log all the details they have, which is a huge stack trace most of the time. A great resource of knowledge, feared by many developers.

So what can you do if you could not recover from an untested corner-case problem? Throw up (probably with a some subclass of RuntimeException) the most meaningful stacktrace annotated with all the context you have. Setup monitoring. And if you run into a frequent problem, fix it.

Stefan Schubert-Peters
  • 5,419
  • 2
  • 20
  • 21
  • Why look into to the source when the javadoc is available and clear ? – Dimitri Aug 12 '11 at 23:53
  • 1
    Javadoc on ServerSocket for example does not tell you, if and how to recover and which kinds of IOExceptions can happen. But from my perspective it is necessary to know something about the device details and how to handle them if I am using a device. In my company we keep saying: It is all documented in the code :-) – Stefan Schubert-Peters Aug 12 '11 at 23:57
  • IOException occurs mostly when a read/write on a device fails. For my point of view, I don't see the need to have information about the device – Dimitri Aug 13 '11 at 00:02
  • The documentation on ServerSocket exceptions is woefully inadequate in actually determining what the actually error condition actually is. Source code and stacktraces are about the only learning tools for dealing with them. – Perception Aug 13 '11 at 00:19
  • @Perception - there's a good reason why the javadoc for I/O exceptions thrown is vague (in general, and in this specific case). If it was specific, it would create an expectation that Java could distinguish the different cases across all implementation platforms. In reality it can't, because the information needed to do this is often not available from the syscall ABIs. – Stephen C Aug 13 '11 at 00:23
  • @Stephen C - You're quite possibly right about that. The fact remains though, that reading the Javadoc for ServerSocket is sufficient to tell you the types of exceptions that occur, but don't really give insight as the *reason* why they occur. Which is what the OP is curious about. – Perception Aug 13 '11 at 00:29
  • @Perception he *is* right about that. The underlying issue is that the Berkeley Sockets API itself is rather under-specified. You really have to know TCP pretty well at the protocol level to understand its behaviour in any high level API. – user207421 Aug 13 '11 at 10:19
1

Yes. The object still exists - May be in an error state in which case it will throw other exceptions until that is rectified.

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
1

If you read the specification for ServerSocket, you will see that it throws an IOException "if an I/O error occurs when waiting for a connection." Is it safe to accept() on the socket again? Yes. Are you going to get the same Exception thrown again? Likely so.

  • Do you mean, that `accept()` is just a guy who tells there are problems, but in fact, it's not a guy who really fails? – Andrey Agibalov Aug 12 '11 at 23:37
  • What do you mean by 'fails'? It will attempt to make a connection. If it cannot, it will throw one of the 4 exceptions to tell you what happened. In this case, IOException is a catchall (as it often is). If one of the other 3 exceptions does not explain the problem, it gets thrown. – Konstantin Tarashchanskiy Aug 12 '11 at 23:42
  • ServerSocket has a queue of clients who want to connect. A call to `accept()` takes the first one out of this queue and tries to establish the connection. Somewhere in the middle of this operation, client ISP go down, so we've failed to establish the connection with this client. Does it affect other clients in the queue? Will `accept()` work for the next client? – Andrey Agibalov Aug 12 '11 at 23:48
  • Nope, It wont affect other clients in the queue. accept in this case will work because every connection between the server and the clients should treated in a separated thread. So, there is no problem – Dimitri Aug 12 '11 at 23:52
1

I have not yet found an easy way to see if an object is still in a usable state. Each object makes its own rules.

In your specific case with ServerSocket I would try one of two different things:

  • Run netstat or some other utility to see what the OS thinks that the socket is doing. If the OS doesn't think it is listening, then something happened. or

  • Write a test program that will throw the exception and see what it does. I do this all the time (especially with proprietary software). It would be harder in the ServerSocket case you picked, since all of the scenarios I can think of (e.g. address in use, insufficient privileges, etc.) would never result in an object being still valid.

Dusty
  • 9
  • 2
1

But SocketTimeoutException is not the only thing that accept() may throw. What does all the other exceptions mean?

According to the javadoc, the declared exceptions are IOException, SecurityException, SocketTimeoutException and IllegalBlockingModeException. The SecurityException and IllegalBlockingModeException only occur in specific contexts and you should not attempt to catch and handle them. (They are not problems you want to try to recover from!) The IOException case occurs when "some other I/O error" occurs. The javadoc does not specify what those I/O errors might be, but possibilities might include such things as:

  • the address to which you have bound is no longer valid
  • a transport protocol error has occurred
  • some error (resource issue, bug ...) occurred in the OS protocol stack

(The fact that the javadoc doesn't say which IOException subclasses might be thrown is a hint that you shouldn't try to do clever things to try to recover. If you do, your code is likely to be platform dependent.)

If I wrap call to accept() with 2 catch clauses: for SocketTimeoutException and IOException, can I still safely use the related ServerSocket instance after I got into IOException clause?

Yes and no. It is safe in the sense that you won't put your application into a worse state than it is already in. On the other hand, there is no guarantee that the next accept call won't fail with the same problem.

If your application is intended to run as an unattended server, I don't think you have much choice but to log the IOException and try again ... hoping that the problem is transient.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

You can find your answer to the javadoc of setsoTimeout, it says :

Enable/disable SO_TIMEOUT with the specified timeout, in milliseconds. With this option set to a non-zero timeout, a call to accept() for this ServerSocket will block for only this amount of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the ServerSocket is still valid. The option must be enabled prior to entering the blocking operation to have effect. The timeout must be > 0. A timeout of zero is interpreted as an infinite timeout.

Dimitri
  • 8,122
  • 19
  • 71
  • 128