Problem with SelectionKey OP_CONNECT

Stanley Brown stanley.brown@zimmer.com
Thu Sep 16 23:45:00 GMT 2004


Doing some further testing I found problems with my attempted patch.  In 
the connect() method I needed to set connectionPending to true.  I also 
could not figure out why this was set to true during the 
SocketTimeOutException so I removed it.

-------------------------
        // Do non-blocking connect.
        try
          {
            socket.connect (remote, NIOConstants.DEFAULT_TIMEOUT);
            connectionPending = true;           
            return true;
          }
        catch (SocketTimeoutException e)
          {
            return false;
          }
-------------------------

Accepting sockets off a server socket channel results in the socket 
being considered not connected and it will throw a 
"NotYetConnectedException" in any attempts to read/write to the socket.  
I fixed this by making the "connected" variable in SocketChannelImpl 
protected and putting this in the ServerSocketChannelImpl accept method:

--------------------------
        ((SocketChannelImpl)socket.getChannel()).connected = 
socket.isConnected();
--------------------------

before returning the socket channel.  Looks hackish but worked.

> Hello,
>
> I have noticed a difference between gcj and Sun's implementation of 
> NIO socket channels.  GCJ is not setting the readyOps when a socket is 
> connectable.  I wrote an example program to illustrate the problem:
> -------------------------
> import java.net.InetSocketAddress;
> import java.nio.channels.*;
> import java.util.Iterator;
>
> public class TestConnect
> {
>    public TestConnect()
>    {
>        try
>        {
>            Selector selector = Selector.open();
>            SocketChannel channel = SocketChannel.open();
>            channel.configureBlocking(false);
>            channel.connect(new InetSocketAddress("gcc.gnu.org", 80));
>            channel.register(selector, SelectionKey.OP_CONNECT);
>                      while (true)
>            {
>                selector.select();
>                Iterator it = selector.selectedKeys().iterator();
>                      while (it.hasNext())
>                {
>                    SelectionKey selKey = (SelectionKey)it.next();
>                                      if (selKey.isConnectable())
>                    {
>                        System.out.println("Connection ready");
>                        System.exit(0);
>                    }
>                }
>            }
>        }
>        catch (Exception ex)
>        {
>            ex.printStackTrace();
>        }
>    }
>      public static void main(String[] args)
>    {
>        new TestConnect();
>    }
> }
> -------------------------
>
> Looking at the SelectorImpl.select(long) method I noticed that there 
> is a section commented out that would add OP_CONNECT if the channel is 
> not connected and the fd is in the write array.  I put it back in like 
> such:
>
> -------------------------
>                      if (key.getNativeFD() == write[i])
>                      {
>                        if (key.channel() instanceof SocketChannel)
>                        {
>                            if ( 
> ((SocketChannel)key.channel()).isConnected ())
>                            {
>                                ops = ops | SelectionKey.OP_WRITE;
>                            }
>                            else
>                            {
>                                ops = ops | SelectionKey.OP_CONNECT;
>                            }
>                        }
>                        else
>                        {
>                            ops = ops | SelectionKey.OP_WRITE;
>                        }
>                     }
> -------------------------
>
> The problem, I believe, is that the SocketChannelImpl.isConnected() 
> returns true on a non-blocking socket even if the finishConnect() has 
> not been called.  So I modified it:
>
> 68d67
> <   private boolean connected;
> 150,152d148
> <            <             connected = true;
> <            195d190
> <         connected = true;
> 203d197
> <         connected = true;
> 212,214c206
> <     if (connected)
> <         connected = socket.isConnected();
> <     return connected;
> ---
> >     return socket.isConnected();
>
> What I basically did was add a "connected" boolean flag.  connect() 
> for blocking sockets can set this flag to true.  Non-blocking sockets 
> can only toggle this by calling finishConnect().  isConnected() will 
> only check the status of the actual socket if the flag is true, 
> otherwise always return false.
>
> Does anyone see a problem with this?  It seems to work fine.
>
> I am using Mohan's gcc (GCC) 3.5.0 20040629 (experimental) on Windows 
> XP SP1
>



More information about the Java mailing list