United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6232954 : (so) client does not see (NIO-created) socket close with SO_TIMEOUT

Details
Type:
Bug
Submit Date:
2005-02-24
Status:
Resolved
Updated Date:
2010-04-02
Project Name:
JDK
Resolved Date:
2005-04-16
Component:
core-libs
OS:
windows_xp
Sub-Component:
java.nio
CPU:
x86
Priority:
P2
Resolution:
Fixed
Affected Versions:
1.4.2_06
Fixed Versions:

Related Reports
Backport:
Backport:

Sub Tasks

Description
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

                                    

Comments
EVALUATION

two issues here, 
(1)preClose() in *SocketChannel classes need to close the socket see#4960962
(2)timeout impl in *SocketAdaptor classes need to throw correct IOException after wakeup by "close"

###@###.### 2005-03-12 05:29:31 GMT
                                     
2005-03-12



Hardware and Software, Engineered to Work Together