Steps: [1] create a socket from ServerSocketChannel.accept; configure it to be blocking; [2] set a non-zero socket SO_TIMEOUT [3] read a byte from the socket's InputStream [4] close the socket (or the socketchannel) [**] the client does not receive the socket being closed immediately We need to set SO_TIMEOUT so that read on the (blocking) socket does not wait indefinitely. Below is the test case to reproduce this. The client used is (linux) telnet. We could reproduce the problem with jdk 1.4.2_03, 1.4.2_06, jdk 1.5 on window XP and jdk 1.4 on linux. import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.SocketAddress; import java.net.Socket; import java.nio.channels.*; import java.util.Iterator; public class B { // static final public boolean USE_A_NEW_THREAD = Boolean.getBoolean("use.a.new.thread"); static final public boolean USE_A_NEW_THREAD = true; private SocketAddress endpoint; private ServerSocketChannel serverSocketChannel; private ServerSocket serverSocket; private Selector selector; public B() { } public void connect() throws IOException { serverSocketChannel = ServerSocketChannel.open(); serverSocket = serverSocketChannel.socket(); serverSocket.bind(new InetSocketAddress(9000), 100); serverSocketChannel.configureBlocking(false); selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } public void select() throws IOException { while (true) { try { if (selector.select(10 * 60 * 1000) == 0) { // 10 minutes System.out.print("nothing being selected.........."); return; } } catch (ClosedSelectorException e) { e.printStackTrace(System.out); return; } catch (NullPointerException e) { e.printStackTrace(System.out); return; } Iterator _iterator = selector.selectedKeys().iterator(); for (; _iterator.hasNext();) { SelectionKey _key = (SelectionKey) _iterator.next(); _iterator.remove(); if (_key.isAcceptable()) { handleAccept(_key); } else if (_key.isReadable()) { handleRead(_key); } else { System.out.println("Unhandled key state: " + _key); } } } } protected void handleAccept(SelectionKey _key) throws IOException { ServerSocketChannel _server = (ServerSocketChannel) _key.channel(); SocketChannel _clientSocketChannel = _server.accept(); Handler _handler = new Handler(this, _clientSocketChannel); _clientSocketChannel.configureBlocking(true); Socket s = _clientSocketChannel.socket(); s.setTcpNoDelay(true); s.setKeepAlive(true); s.setSoTimeout(1000000); if (USE_A_NEW_THREAD) { System.out.println("a new thread is spawned"); (new Thread(_handler)).start(); } else { _handler.run(); } } protected void handleRead(SelectionKey _key) throws IOException { throw new IllegalStateException("......... not implemented .........."); } public static class Handler implements Runnable { private SocketChannel channel; private B driver; public Handler(B _driver, SocketChannel _channel) { driver = _driver; channel = _channel; } public void run() { try { System.out.println("invoke setSoTimeout"); InputStream is = channel.socket().getInputStream(); int b = is.read(); System.out.println("sleep 5 seconds and then close the channel"); Thread.sleep(1000 * 5); System.out.println("socket to be closed: " + channel.socket()); System.out.println("socket to be closed: " + channel.socket()); System.out.println("socket to be closed: " + channel.socket()); // channel.socket().close(); channel.close(); // channel.close(); System.out.println("connection closed"); } catch (Exception e) { e.printStackTrace(System.out); } } } final static public void main(String[] argv) { try { B b = new B(); b.connect(); b.select(); Thread.sleep(1000 * 60 * 20); // twenty minutes } catch (Exception e) { e.printStackTrace(System.out); } } } ###@###.### 2005-2-24 23:54:47 GMT
|