Name: jl125535 Date: 07/13/2004
FULL PRODUCT VERSION :
java version "1.5.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta3-b57)
Java HotSpot(TM) Client VM (build 1.5.0-beta3-b57, mixed mode)
java version "1.4.2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2-b28)
Java HotSpot(TM) Client VM (build 1.4.2-b28, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
A DESCRIPTION OF THE PROBLEM :
There are no JavaDocs for ServerSocketChannel.close() -- the reader must default to the Channel.close() docs, which are not specific about the function of the close() method on a non-blocking ServerSocketChannel and the releasing of OS resources. Specifically, after closing a non-blocking ServerSocketChannel that has been registered with a Selector, the isOpen() method will return false. There is no reason for the developer to believe that the close operation is not complete at this point. However, the port has not been freed to the OS...and a subsequent open()/bind() to the same port number will fail. Even if you have de-registered the channel with the selector via SelectionKey.cancel(), the resource is still not freed. You must make another call to Selector.select() in order for the resources to be freed. In our case, our application knows that there are no other resources registered to the Selector and so there was no reason (or so we thought) to make another call to the Selector.
This behavior is _hinted_ at in the Selector documentation...in this line:
"Each key in the cancelled-key set is removed from each key set of which it is a member, and its channel is deregistered."
However, that says nothing about completing a close operation or freeing underlying resources. Either the documentation needs to be more explicit or there is a bug with this behavior.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expect the ServerSocketChannel.close() method to free the port back to the OS.
ACTUAL -
After successfully executing a call to ServerSocketChannel.close(), the port is still in use.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.net.BindException: Address already in use: bind
at sun.nio.ch.Net.bind(Native Method)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:119)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:59)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:52)
at test.Test.main(Test.java:37)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.nio.channels.*;
import java.net.*;
import java.io.*;
public class Test
{
public static void main(String[] args)
{
try
{
Selector _selector = Selector.open();
ServerSocketChannel _server = ServerSocketChannel.open();
_server.configureBlocking(false);
_server.socket().bind(new InetSocketAddress(8080));
SelectionKey key =
_server.register(_selector, SelectionKey.OP_ACCEPT);
Thread.sleep(100);
_server.close();
key.cancel();
if (_server.isOpen())
System.out.println("The ServerSocket was not closed!");
_server = null;
Thread.sleep(100);
// do this select...and it works!
//_selector.select(100);
_server = ServerSocketChannel.open();
_server.configureBlocking(false);
_server.socket().bind(new InetSocketAddress(8080));
key = _server.register(_selector, SelectionKey.OP_ACCEPT);
Thread.sleep(100);
_server.close();
key.cancel();
_selector.close();
}
catch (IOException e)
{
System.out.println("Bang!");
e.printStackTrace();
}
catch (InterruptedException e)
{
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Make an extraneous call to Selector.select() after calling ServerSocketChannel.close().
(Incident Review ID: 285702)
======================================================================