JavaNIO: IOException: 破裂的管道是什么意思?

对于我的一些 JavaNIO 连接,当我有一个 SocketChannel.write(ByteBuffer)调用时,它抛出一个 IOException: “故障管道”。

是什么导致了“管道破裂”,更重要的是,是否有可能从这种状态中恢复过来?如果无法恢复,这似乎是一个好的迹象,表明发生了不可逆的问题,我应该简单地关闭这个套接字连接。这个假设合理吗?当套接字连接仍然处于正确连接状态(而不是在某个时刻失败的工作连接)时,是否曾经发生过这种 IOException

另外,在尝试 SocketChannel.write()之前总是调用 SocketChannel.isConnected()是明智的吗? 如果是这样,我是否也可以假设连接是“断开的”,如果 SocketChannel.isConnected()SocketChannel.isConnectionPending()都是 false,那么连接应该关闭?

谢谢!

165348 次浏览

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".

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.

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 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.