JDK-4737146 : (so) key.isConnectable() true even after connection complete
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 1.4.1
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2002-08-27
  • Updated: 2002-12-23
  • Resolved: 2002-10-26
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.2 mantisFixed
Related Reports
Relates :  
Description

Name: gm110360			Date: 08/26/2002


FULL PRODUCT VERSION :
j2sdk-1_4_1-rc-windows-i586.exe

Java 2 Enterprise Edition version 1.3.1, build 1.3.1-b17

FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
I have a NIO Client and Server using non-bloacking mode.
When client connects to the server the selector respond
back saying
Connecting ....
Processing selecion key.isConnectable()=true key.isReadable
()=false

which is correct. Then i wait till finishConnect() and
write something on the stream to send to server. Server
respond back.

This time when the selector returns back on the client side
it still show me isConnectable() = true ??

Processing selecion key.isConnectable()=true key.isReadable
()=true

And the while loop
while ( selector.select() > 0 ) {
keeps on executing and behave like while(true).






REGRESSION.  Last worked in version 1.4

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Please find the source attached.
1.Execute the Server
2. Execute the client


EXPECTED VERSUS ACTUAL BEHAVIOR :
The client will keep on recursively sending data to server
as the loop
while ( selector.select() > 0 ) {
behaves as if while(true)
this happens on the client side


ERROR MESSAGES/STACK TRACES THAT OCCUR :
This is a problem of selector reporting.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
######################### CLIENT CODE ##################################
import java.nio.*;
import java.nio.charset.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

class NIOClient {
	public static void main(String[] args) {
		System.out.println("Connecting ....");
		connect();
		System.out.println("Connected.");
	}

	public static void connect() {
		try{
			java.net.InetAddress lh =
java.net.InetAddress.getLocalHost();
			java.net.InetSocketAddress socketAddress = new
java.net.InetSocketAddress(lh, 5555);
			java.nio.charset.Charset charset =
java.nio.charset.Charset.forName("us-ascii");
			java.nio.charset.CharsetEncoder encoder =
charset.newEncoder();
			java.nio.charset.CharsetDecoder decoder =
charset.newDecoder();

			//allocate buffers
			ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
			CharBuffer charBuffer = CharBuffer.allocate(1024);

			java.nio.channels.SocketChannel channel =
java.nio.channels.SocketChannel.open();

			// make the channel as non-blocking
			channel.configureBlocking(false);

			// for a non-blocking io it should written immediately
			channel.connect(socketAddress);

			//get the selector
			//java.nio.channels.Selector selector =
java.nio.channels.Selector.open();
			java.nio.channels.Selector selector =
java.nio.channels.spi.SelectorProvider.provider().openSelector();

			//register the channel
			channel.register(selector,
java.nio.channels.SelectionKey.OP_CONNECT |
java.nio.channels.SelectionKey.OP_READ );

			while ( selector.select() > 0 ) {
				// get the set of ready object
				java.util.Set keys = selector.selectedKeys();

				java.util.Iterator readyItor = keys.iterator();
				
				//walk through the set
				while ( readyItor.hasNext() ) {

					// get the ket from the set
					java.nio.channels.SelectionKey key =
(java.nio.channels.SelectionKey)readyItor.next();

					//remove the current entry
					readyItor.remove();

					// get the channel
					java.nio.channels.SocketChannel
keyChannel = (java.nio.channels.SocketChannel)key.channel();

					System.out.println("Processing selecion
key.isConnectable()=" + key.isConnectable() + " key.isReadable()=" +
key.isReadable() );
					
					if ( key.isConnectable() ) {

						//Finish connection
						if (
keyChannel.isConnectionPending() ) {
							keyChannel.finishConnect
();
						}

						String request = "Hello, how
are you ?\n";
						keyChannel.write(encoder.encode
( CharBuffer.wrap(request) ));

						//clear the buffers
						buffer.clear();
						charBuffer.clear();
					} else if( key.isReadable() ) {

						ByteBuffer byteBuffer =
ByteBuffer.allocate(1024);
						int nbytes = keyChannel.read(
byteBuffer );
						byteBuffer.flip();
						String result = decode(
byteBuffer );
						System.out.println(result);

						//clear the buffers
						buffer.clear();
						charBuffer.clear();
					} else {
						System.out.println("Ooops");
					}

				}

			}

		} catch ( java.lang.IllegalArgumentException iae )	{
			iae.printStackTrace();
		} catch ( java.nio.channels.NotYetConnectedException nyce ) {
			nyce.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static String decode( ByteBuffer byteBuffer ) throws
java.nio.charset.CharacterCodingException{
		Charset charset = Charset.forName("us-ascii");
		CharsetDecoder decoder = charset.newDecoder();
		CharBuffer charBuffer = decoder.decode( byteBuffer );
		String result = charBuffer.toString();
		return result;
	}

}





######################### SERVER CODE ##################################


import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

class NIOServer implements Runnable {
	int port = 5555;
	static final int BUFSIZE = 30;
	java.nio.channels.Selector selector = null;
	java.nio.channels.ServerSocketChannel selectableChannel = null;
	java.util.Vector list = new java.util.Vector();
	int keysAdded = 0;

	static String QUIT_SERVER = "quit";
	static String SHUTDOWN = "shutdown";

	public NIOServer() {
	}

	public NIOServer(int port) {
		this.port = port;
	}

	public void initialize () throws java.io.IOException {
		this.selector = java.nio.channels.spi.SelectorProvider.provider
().openSelector();
		this.selectableChannel =
java.nio.channels.ServerSocketChannel.open();
		this.selectableChannel.configureBlocking(false);
		
		java.net.InetAddress lh = java.net.InetAddress.getLocalHost();
		java.net.InetSocketAddress isa = new java.net.InetSocketAddress
(lh, this.port);

		this.selectableChannel.socket().bind(isa);
	}

	protected void finalize() throws java.io.IOException {
		this.selectableChannel.close();
		this.selector.close();
	}

	public void log(String msg) {
		System.out.println(msg);
	}

	public void acceptConnections() {
		try	{
			//register the channel
			java.nio.channels.SelectionKey acceptKey =
this.selectableChannel.register(this.selector,
java.nio.channels.SelectionKey.OP_ACCEPT);
			
			this.log("Acceptor loop...");

			// walk through the keys
			while ( (this.keysAdded = acceptKey.selector().select
()) > 0 )	{
				this.log("Selector returned " + this.keysAdded
+ " ready for IO operation.");

				//get the ready set of objects
				java.util.Set readyKeys = selector.selectedKeys
();
				java.util.Iterator i = readyKeys.iterator();

				while( i.hasNext() ) {
					java.nio.channels.SelectionKey key =
(java.nio.channels.SelectionKey)i.next();
					i.remove();

					if ( key.isAcceptable() ) {
						// get the channel accociated
with this key
					
	java.nio.channels.ServerSocketChannel nextReady =
(java.nio.channels.ServerSocketChannel)key.channel();
						
						this.log("Processing selecion
key read=" + key.isReadable() + " write=" + key.isWritable() + " accept=" +
key.isAcceptable() );

						java.nio.channels.SocketChannel
channel = nextReady.accept();
						channel.configureBlocking
(false);

						java.nio.channels.SelectionKey
readyKey =
								channel.register
(this.selector, java.nio.channels.SelectionKey.OP_READ);
						ChannelCallback cc = new
ChannelCallback(channel);
						readyKey.attach(cc);

						//add to the list
						this.list.add(cc);
					} else if ( key.isReadable() ) {
						// get the channel accociated
with this key
					
	java.nio.channels.SelectableChannel nextReady =
(java.nio.channels.SelectableChannel)key.channel();
					
						this.log("Processing selecion
key read=" + key.isReadable() + " write=" + key.isWritable() + " accept=" +
key.isAcceptable() );
						ChannelCallback cc =
(ChannelCallback)key.attachment();
						this.readMessage(cc);
					}
				}
			}
		} catch (Exception e) {
		}

		this.log("End of acceptor loop.");
	}

	public void writeMessage(java.nio.channels.SocketChannel channel,
String message) throws java.io.IOException {
		ByteBuffer buf = ByteBuffer.wrap( message.getBytes() );
		int nbytes = channel.write(buf);
		this.log("Wrote " + nbytes + " to channel.");
	}

	public String decode( ByteBuffer byteBuffer ) throws
java.nio.charset.CharacterCodingException{
		Charset charset = Charset.forName("us-ascii");
		CharsetDecoder decoder = charset.newDecoder();
		CharBuffer charBuffer = decoder.decode( byteBuffer );
		String result = charBuffer.toString();
		return result;
	}

	public void readMessage( ChannelCallback callback ) throws
java.lang.InterruptedException {
		ByteBuffer byteBuffer = ByteBuffer.allocate(BUFSIZE);
		try	{
			int nbytes = callback.getChannel().read( byteBuffer );
			
			byteBuffer.flip();
			String result = this.decode( byteBuffer );

			if (result.indexOf("quit") >= 0 ) {
				callback.getChannel().close();
			} else if ( result.indexOf("shutdown") >= 0 ){
				callback.getChannel().close();
				throw new java.lang.InterruptedException();
	
			} else {
				callback.append( result );
				if ( result.indexOf("\n") >= 0 ) {
					//if we are done with the line then we
execute the callback
					callback.execute();
				}
			}
		} catch (java.io.IOException ioe) {
			//System.out.println("Removing the channel from the
list.");
			this.list.remove(callback);
		}
	}


	public static void main(String[] args)
	{
		System.out.println("Hello World!");
		NIOServer nioServer = new NIOServer();
		try	{
			nioServer.initialize();
		} catch(Exception e) {
			e.printStackTrace();
		}

		Thread t = new Thread(nioServer);
		t.start();

		try	{
			nioServer.acceptConnections();
		} catch (Exception e)	{
			e.printStackTrace();
		}
	}

	public void run() {
		while (true) {
			System.out.println(list.size());
			java.util.Enumeration enum = list.elements();
			while( enum.hasMoreElements() ) {
				ChannelCallback cc = (ChannelCallback)
(enum.nextElement());
				try	{
					writeMessage(cc.getChannel(), "I am
fine thanx.");
				} catch (Exception e){
					e.printStackTrace();
					list.remove(cc);
				}
			}

			try	{
				Thread.sleep(10000);
			} catch (Exception e){}
		}
	}

	class ChannelCallback {
		private SocketChannel channel;
		private StringBuffer buffer;

		public ChannelCallback( java.nio.channels.SocketChannel
channel ) {
			this.channel = channel;
			buffer = new StringBuffer();
		}

		public void execute() throws IOException {
			System.out.println(this.buffer.toString());
			writeMessage( this.channel, this.buffer.toString() );
			buffer = new StringBuffer();
		}

		public SocketChannel getChannel() {
			return this.channel;
		}

		public void append(String values) {
			this.buffer.append(values);
		}
	};
}








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

CUSTOMER WORKAROUND :
If you execute this with the previous version
java version "1.4.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build
1.4.0_01-b03)
Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)

The same sample code works fine.

Release Regression From : 1.4.0_01
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

(Review ID: 163533) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mantis FIXED IN: mantis INTEGRATED IN: mantis mantis-b05 VERIFIED IN: mantis-beta
14-06-2004

EVALUATION We have changed isConnectable to behave in a more intuitive fashion. ###@###.### 2002-10-15
15-10-2002