JDK-4727975 : (so) Cannot close a channel-based socket if timeout specified
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 1.4.1
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86
  • Submitted: 2002-08-07
  • Updated: 2003-11-04
  • Resolved: 2003-11-04
Related Reports
Duplicate :  
Relates :  
Description

Name: nt126004			Date: 08/07/2002


FULL PRODUCT VERSION :
java version "1.4.1-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-beta-b14)
Java HotSpot(TM) Client VM (build 1.4.1-beta-b14, mixed mode)


FULL OPERATING SYSTEM VERSION : Debian GNU/Linux 2.2r7
(potato)
(Linux kernel 2.2.19)


ADDITIONAL OPERATING SYSTEMS :
also fails on Windows 98 with J2SDK 1.4.0



EXTRA RELEVANT SYSTEM CONFIGURATION :
java version "1.4.1-beta"


A DESCRIPTION OF THE PROBLEM :
For a Socket retrieved from a SocketChannel created from
a ServerSocketChannel, closing the Socket object does not
really close the socket.

Operations on the Socket object do act as if it the socket
is closed, but the netstat command shows that the socket
is still connected, and a read on the corresponding
client socket indicates that the connection is still...
well...connected (it still blocks, and doesn't give an
error).

The problems occurs with:
- J2SDK version 1.4.1beta1 on Linux (kernel 2.2.19)
- J2SDK version 1.4.0 on Linux
- J2SDK version 1.4.0 on Windows 98




STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the attached program.  Specifically,
notice the (hopefully) self-explanatory messages marked
with double asterisks.

For additional visibility of the symptoms, run "netstat -c"
simultaneously.




REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package test;
import java.util.*;
import java.io.*;
import java.nio.channels.*;
import java.net.*;


public class BugTest
{


    public static final int proxyPort = 8000;
    public static final int proxyTimeOut = 5 * 1000;


    protected ServerSocketChannel listenerChannel;



    static class ConnectionServicer
	implements Runnable
    {
	Socket browserSocket;
	InputStream browserInputStream;
	OutputStream browserOutputStream;


	ConnectionServicer( Socket browserSocket )
	{
	    this.browserSocket = browserSocket;
	} // ConnectionServicer( ... )



	private boolean serviceQuery()
	    throws IOException
	{
	    try {
		int chInt = browserInputStream.read();
		System.err.println( "server read: '" + (char) chInt + "'" );
	    }
	    catch ( SocketTimeoutException e ) {
		System.err.println( "server socket timeout detected" );
	    
		return false;
	    }

	    browserOutputStream.write( (byte) 'R' );
	    browserOutputStream.flush();


	    return true;
	} // serviceQuery(...)


	private void serviceConnection()
	    throws IOException
	{
	    browserInputStream = browserSocket.getInputStream();
	    browserOutputStream = browserSocket.getOutputStream();

	    boolean isOpen;
	    do {
		isOpen = serviceQuery();
	    } while ( isOpen );
	} // serviceConnection()


	public void run()
	{
	    try {
		serviceConnection();
	    }
	    catch ( IOException e ) {
		throw new RuntimeException( e );
	    }
	    finally {
		try {
		    if ( null != browserSocket ) {
			System.err.println( "server closing socket:" );
			System.err.println( "  browserSocket = " + browserSocket );
			System.err.println( "  browserSocket.isClosed() = " +
browserSocket.isClosed() );
			browserSocket.close();
			System.err.println( "  browserSocket = " + browserSocket );
			System.err.println( "  browserSocket.isClosed() = " +
browserSocket.isClosed() );
		    }
		}
		catch ( IOException e ) {
		    assert false;
		    e.printStackTrace();
		}
	    }
	} // run()


    } // class ConnectionServicer





    protected BugTest( int port )
	throws IOException
    {
	listenerChannel = ServerSocketChannel.open();
	ServerSocket listenerSocket = listenerChannel.socket();
	listenerSocket.bind( new InetSocketAddress( "localhost",
						    proxyPort ) );
	new Thread()
	    {
		public void run()
		{
		    //while ( true ) {
			try {
			    SocketChannel browserChannel =
				listenerChannel.accept();
			    final Socket browserSocket =
				browserChannel.socket();
			    browserSocket.setSoTimeout( proxyTimeOut );


			    Thread thread =
				new Thread(
				    new ConnectionServicer( browserSocket ),
				    "c"
				    )
				    {
					public void run()
					{
					    super.run();
					} // run()
				    };
			    thread.start();
			}
			catch ( IOException e ) {
			    assert false;
			    System.err.println (
				new RuntimeException( "error accepting connection", e )
				    );
			}
			//} // while
		} // run()
	    }
	    .start();
    } // BugTest()


    private static void runTest()
	throws Exception
    {
	Thread.sleep( 2000 );


	Socket clientSocket = new Socket( "localHost", proxyPort );
	System.err.println( "clientSocket = " + clientSocket );

	Writer writer =
	    new OutputStreamWriter( clientSocket.getOutputStream() );
	Reader reader = new InputStreamReader( clientSocket.getInputStream() );

	System.err.println( "writing first query:" );
	writer.write( 'Q' );
	writer.flush();
	Thread.sleep( 1000 );
	{
	    System.err.println( "reading first response:" );
	    int response = reader.read();
	    System.err.println( "client read: '" + (char) response + "'" );
	}


	System.err.println( "clientSocket = " + clientSocket );
	System.err.println( "clientSocket.isClosed() = " + clientSocket.isClosed() );

	System.err.println( "client sleeping 10..." );
	Thread.sleep( 10 * 1000 );
	System.err.println( "...client slept 10" );

	System.err.println( "clientSocket = " + clientSocket );
	System.err.println( "clientSocket.isClosed() = " + clientSocket.isClosed() );


	System.err.println( "writing second query:" );
	writer.write( 'Q' );
	writer.flush();
	Thread.sleep( 1000 );
	{
	    System.err.println( "** If this hangs after the next message, you're seeing
the buggy behavior." );
	    
	    System.err.println( "reading second response:" );
	    int response = reader.read();
	    System.err.println( "** If you see this, then you're not setting the buggy
behavior." );

	    System.err.println( "client read: '" + (char) response + "'" );
	}
    } // runTest()




    public static void main( String[] args )
	throws Exception
    {
	new BugTest( proxyPort );
	runTest();
    } // main( ... )


} // class BugTest

---------- END SOURCE ----------

CUSTOMER WORKAROUND :
None of:
- closing the SocketChannel object
- closing the Socket object
- closing the input or output streams
seems to get the socket closed.
(Review ID: 160179) 
======================================================================

Comments
EVALUATION Probable duplicate of 4724030/4726957. -- ###@###.### 2002/8/7
08-10-0173