This question already has answers here:
How to fix java.net.SocketException: Broken pipe?
(10 answers)
Closed 3 years ago.
For some of my Java NIO connections, when I have a SocketChannel.write(ByteBuffer) call, it throws an IOException: "Broken pipe".
What causes a "broken pipe", and, more importantly, is it possible to recover from that state? If it cannot be recovered, it seems this would be a good sign that an irreversible problem has occurred and that I should simply close this socket connection. Is that a reasonable assumption? Is there ever a time when this IOException would occur while the socket connection is still being properly connected in the first place (rather than a working connection that failed at some point)?
On a side note, is it wise to always call SocketChannel.isConnected() before attempting a SocketChannel.write(), and if so, can I also assume that the connection is "broken" and should be closed if both SocketChannel.isConnected() and SocketChannel.isConnectionPending() are both false?
Thanks!
What causes a "broken pipe", and more importantly, is it possible to recover from that state?
It is caused by something causing the connection to close. (It is not your application that closed the connection: that would have resulted in a different exception.)
It is not possible to recover the connection. You need to open a new one.
If it cannot be recovered, it seems this would be a good sign that an irreversible problem has occurred and that I should simply close this socket connection. Is that a reasonable assumption?
Yes it is. Once you've received that exception, the socket won't ever work again. Closing it is is the only sensible thing to do.
Is there ever a time when this IOException would occur while the socket connection is still being properly connected in the first place (rather than a working connection that failed at some point)?
No. (Or at least, not without subverting proper behavior of the OS'es network stack, the JVM and/or your application.)
Is it wise to always call SocketChannel.isConnected() before attempting a SocketChannel.write() ...
In general, it is a bad idea to call r.isXYZ() before some call that uses the (external) resource r. There is a small chance that the state of the resource will change between the two calls. It is a better idea to do the action, catch the IOException (or whatever) resulting from the failed action and take whatever remedial action is required.
In this particular case, calling isConnected() is pointless. The method is defined to return true if the socket was connected at some point in the past. It does not tell you if the connection is still live. The only way to determine if the connection is still alive is to attempt to use it; e.g. do a read or write.
Broken pipe simply means that the connection has failed. It is reasonable to assume that this is unrecoverable, and to then perform any required cleanup actions (closing connections, etc). I don't believe that you would ever see this simply due to the connection not yet being complete.
If you are using non-blocking mode then the SocketChannel.connect method will return false, and you will need to use the isConnectionPending and finishConnect methods to insure that the connection is complete. I would generally code based upon the expectation that things will work, and then catch exceptions to detect failure, rather than relying on frequent calls to "isConnected".
Broken pipe means you wrote to a connection that is already closed by the other end.
isConnected() does not detect this condition. Only a write does.
is it wise to always call SocketChannel.isConnected() before attempting a SocketChannel.write()
It is pointless. The socket itself is connected. You connected it. What may not be connected is the connection itself, and you can only determine that by trying it.
You should assume the socket was closed on the other end. Wrap your code with a try catch block for IOException.
You can use isConnected() to determine if the SocketChannel is connected or not, but that might change before your write() invocation finishes. Try calling it in your catch block to see if in fact this is why you are getting the IOException.
Related
This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 7 years ago.
From (Java Network Programming fourth edition):
To tell if a socket is currently open, you need to
check that isConnected() returns true and isClosed() returns false. For an example:
boolean connected = socket.isConnected() && ! socket.isClosed();
I need to find a way to discover as soon as possible that the client has disconnected from the Server Socket. Using the trick described above,I have tried the following :
Socket socket = ...;
while (socket.isConnected() && !socket.isClosed()) {
// do something ...
// here, the client is always connected
}
// client is disconnected
The above approach works for me, but it is always correct?. it detects all the cases?
Depending on the application, catching exceptions intelligently would seem like a good solution. The requirement, however, is that you actually wants to send/do something to the client. Possibly a combination of the two approaches suits your specific application. You could try seeing:
Java detect lost connection
The book is wrong, if that's what it really says. isConnected() has nothing to do with whether a socket is currently open. It tells you whether it has ever been connected, which is not at all the same thing.
isOpen() does tell you whether the socket is open, but that doesn't tell you anything about the state of the connection. The test for whether the connection is still open is whether:
read() has returned -1
readLine() has returned null
readXXX() has thrown EOFException for any other X
... all of which indicate that the peer has closed the connection, or
any read or write method has thrown an IOException with the text 'connection reset'.
I'm developing an application using Java Smack API. I use the PacketCollector.java class' nextResult() method to receive the next incoming message. (According the doc, this method blocks until there is input.)
http://www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware/smack/PacketCollector.html
I have a question concerning what if the connection is abruptly broken (say, by network disconnection and so on), how do I know or how can I catch the exception?
The nextResult() call will wait until a packet that matches the filter arrives. Looking at the source I think it would even wait after a disconnect and reconnect, as long as you use the same connection instance.
You shouldn't really use nextResult(), use nextResult(long) instead. nextResult() does not throw an exception if the connection is disconnected for whatever reason and there is no good reason to use nextResult() instead of nextResult(long) with an reasonable timeout value.
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.
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.
Yes. The object still exists - May be in an error state in which case it will throw other exceptions until that is rectified.
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.
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.
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.
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.
This question already has answers here:
How to fix java.net.SocketException: Broken pipe?
(10 answers)
Closed 3 years ago.
For some of my Java NIO connections, when I have a SocketChannel.write(ByteBuffer) call, it throws an IOException: "Broken pipe".
What causes a "broken pipe", and, more importantly, is it possible to recover from that state? If it cannot be recovered, it seems this would be a good sign that an irreversible problem has occurred and that I should simply close this socket connection. Is that a reasonable assumption? Is there ever a time when this IOException would occur while the socket connection is still being properly connected in the first place (rather than a working connection that failed at some point)?
On a side note, is it wise to always call SocketChannel.isConnected() before attempting a SocketChannel.write(), and if so, can I also assume that the connection is "broken" and should be closed if both SocketChannel.isConnected() and SocketChannel.isConnectionPending() are both false?
Thanks!
What causes a "broken pipe", and more importantly, is it possible to recover from that state?
It is caused by something causing the connection to close. (It is not your application that closed the connection: that would have resulted in a different exception.)
It is not possible to recover the connection. You need to open a new one.
If it cannot be recovered, it seems this would be a good sign that an irreversible problem has occurred and that I should simply close this socket connection. Is that a reasonable assumption?
Yes it is. Once you've received that exception, the socket won't ever work again. Closing it is is the only sensible thing to do.
Is there ever a time when this IOException would occur while the socket connection is still being properly connected in the first place (rather than a working connection that failed at some point)?
No. (Or at least, not without subverting proper behavior of the OS'es network stack, the JVM and/or your application.)
Is it wise to always call SocketChannel.isConnected() before attempting a SocketChannel.write() ...
In general, it is a bad idea to call r.isXYZ() before some call that uses the (external) resource r. There is a small chance that the state of the resource will change between the two calls. It is a better idea to do the action, catch the IOException (or whatever) resulting from the failed action and take whatever remedial action is required.
In this particular case, calling isConnected() is pointless. The method is defined to return true if the socket was connected at some point in the past. It does not tell you if the connection is still live. The only way to determine if the connection is still alive is to attempt to use it; e.g. do a read or write.
Broken pipe simply means that the connection has failed. It is reasonable to assume that this is unrecoverable, and to then perform any required cleanup actions (closing connections, etc). I don't believe that you would ever see this simply due to the connection not yet being complete.
If you are using non-blocking mode then the SocketChannel.connect method will return false, and you will need to use the isConnectionPending and finishConnect methods to insure that the connection is complete. I would generally code based upon the expectation that things will work, and then catch exceptions to detect failure, rather than relying on frequent calls to "isConnected".
Broken pipe means you wrote to a connection that is already closed by the other end.
isConnected() does not detect this condition. Only a write does.
is it wise to always call SocketChannel.isConnected() before attempting a SocketChannel.write()
It is pointless. The socket itself is connected. You connected it. What may not be connected is the connection itself, and you can only determine that by trying it.
You should assume the socket was closed on the other end. Wrap your code with a try catch block for IOException.
You can use isConnected() to determine if the SocketChannel is connected or not, but that might change before your write() invocation finishes. Try calling it in your catch block to see if in fact this is why you are getting the IOException.
ClientAbortException: java.net.SocketException: Broken pipe
If I am wright, this happens when user aborts current operation or makes another request, before the last one is finished.
Can this reflects on browsing user or is this (always) just a Catalinas exception?
Are there any ways to avoid this exception?
Try defining a filter for all resources in your webapp, and catch & discard the exception there. I'm not sure if it will work, but give it a try.
In 99% of the cases this exception can be ignored, because it's mainly called by user disconnects (i-net breaks, user hits stop, closes browser, etc)