• Post Reply Bookmark Topic Watch Topic
  • New Topic

Socket Exception when closing Streams on a Socket

 
Gaz Lynch
Greenhorn
Posts: 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi

I have 2 processes - a Server socket and a client socket. If I close the Client process first, and then try closing down the Streams on the Server process, I get a SocketException with message "Socket is closed" when I try and close the 2nd Stream. It does not matter on the order of the Stream being closed down, the exception is always thrown when I try and close the second stream. The code snippets are below:

SERVER
=======

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerSocketTest {

public static void main(String args[]) {

try {
ServerSocket ss = new ServerSocket(9999);
Socket s = ss.accept();

// Get refs to streams...
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();

// sleep to let client shutdown first...
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.err.println(e);
}

System.err.println("B4 inClose: isBound=" + s.isBound());
System.err.println("B4 inClose: isClosed=" + s.isClosed());
System.err.println("B4 inClose: isConnected=" + s.isConnected());
System.err.println("B4 inClose: isInputShutdown=" + s.isInputShutdown());
System.err.println("B4 inClose: isOutputShutdown=" + s.isOutputShutdown());

s.getInputStream().close();

System.err.println("After inClose: isBound=" + s.isBound());
System.err.println("After inClose: isClosed=" + s.isClosed());
System.err.println("After inClose: isConnected=" + s.isConnected());
System.err.println("After inClose: isInputShutdown=" + s.isInputShutdown());
System.err.println("After inClose: isOutputShutdown=" + s.isOutputShutdown());

s.getOutputStream().close(); // will break here with SocketException!

System.err.println("After outClose: isBound=" + s.isBound());
System.err.println("After outClose: isClosed=" + s.isClosed());
System.err.println("After outClose: isConnected=" + s.isConnected());
System.err.println("After outClose: isInputShutdown=" + s.isInputShutdown());
System.err.println("After outClose: isOutputShutdown=" + s.isOutputShutdown());

s.close();

} catch (Exception e) {
System.err.println(e);
}
}
}

CLIENT
======
import java.net.Socket;

public class ClientSocket {

public static void main(String args[]) {

try {

Socket s = new Socket("localhost", 9999);

try {
// sleep to leave connection up for a while...
Thread.sleep(2000);
} catch (InterruptedException e) {
System.err.println(e);
}

s.close();

} catch (Exception e) {
System.err.println(e);
}
}
}

The debug shows that isClosed() is set to 'true' after the first call to s.getInputStream().close(). The Sun API Socket class getOutputStream() has a call to isClosed() at the start of the method - it then throws the SocketException that I get. Why does the SocketImpl do this before I get a chance to call a.getOutputStream().close()?

One final thing, the calls to s.isInputShutdown() and s.isOuputShutdown always seem to return false even if the Streams have had their .close() method called.

Any ideas/help here greatly appreciated.

Thanks
Gaz
 
Gaz Lynch
Greenhorn
Posts: 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, I know what's going on now - I needed something to do on Friday afternoon anyhow!

Basically if you call either getOutputStream.close() or getInputStream().close(), the underlying Sun implementation will close the Socket.

Here's what's happening under the covers in the Sun code:

s.getInputStream() is called on the Socket class.
The Socket class holds a reference to the SocketImpl class.
The SocketImpl class is abstract and forces sublclasses to extend it' s getInputStream() method.
The PlainSocketImpl extends SocketImpl.

PlainSocketImpl has a getInputStream() method that returns a SocketInputStream. When the stream is created for the first time, the PlainSocketImpl object is passed into the Constructor.

The SocketInputStream class has a close() method on it. The snippet of code below shows how the socket is closed:
<pre>
/**
* Closes the stream.
*/
private boolean closing = false;
public void close() throws IOException {
// Prevent recursion. See BugId 4484411
if (closing)
return;
closing = true;
if (socket != null) {
if (!socket.isClosed())
socket.close();
} else
impl.close();
closing = false;
}
</pre>

So, it seems that out PlainSocketImpl is getting closed for us, hence the SocketException being thrown in Socket.getOutputStream() when I call it after Socket.getInputStream().

I've not had a look at the reason why the calls to s.isInputShutdown() and s.isOuputShutdown always seem to return false even if the Streams have had their .close() method called though - any thoughts appreciated.

Thanks
G
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!