获取SelectedKeys&切换操作

时间:2012-05-10 11:09:22

标签: java sockets nio

我创建了这个异步客户端套接字,它连接到服务器并始终保持连接打开,并在与服务器断开连接时自动重新连接。

无论如何我的问题是:在初始化连接时,我将操作注册为连接操作(SelectionKey.OP_Connect)。

现在,当我在选择器的选定键之间进行迭代时,我希望它输入控制语句isconnectable并更改操作,如控制语句中所示。

不幸的是,我没有获得任何选定的密钥。我哪里可能出错?

        import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.SocketChannel;
    import java.util.Iterator;
    import java.util.Set;
    import java.util.logging.Level;
    import java.util.logging.Logger;



    /*
     * @author kewin
     */
    public class clientEvent implements Runnable{
        private static volatile boolean connected=false;
        private SocketChannel channel;
        private Selector selector;
        private ByteBuffer readBuffer = ByteBuffer.allocate(8192);
        private QueueData Qdata;
        private SelectionKey selectKey;



        private  void initiateConnection() {
    try {
    selector= Selector.open();//initializes the Selector Thread
    channel = SocketChannel.open();
    channel.configureBlocking(false);
    channel.connect(new InetSocketAddress(InetAddress.getByName("127.0.0.1"),2000));
    Thread.sleep(50);//Sleeps for a few Seconds to allow decent connection completion
    channel.register(selector,SelectionKey.OP_CONNECT);//Registers the channel with the a selector and a selection key
    if(channel.finishConnect())/*checks whether the connection is finished*/{
        channel.register(selector,SelectionKey.OP_READ);//Registers the channel with the a selector and a selection key
        connected=true;}
   } catch(Exception ex){connected=false;} 
 }


        private void ConnectAndMonitor(){
           while(true){
            try {
               readBuffer.clear();
               channel.read(readBuffer);
            } catch (Exception ex) {
                    connected=false
                try {
                    channel.close()
                    selector.close();
                } catch (Exception e) {         
                }
                   if(!connected){
                    initiateConnection();
                    connected=true;
               }
            }
           }
        }


        @Override
        public void run() {
            try{
                new Thread(){@Override public void run(){ConnectAndMonitor()}}.start(); 

                while(true){
                   if(!connected){
                       System.out.println("not connected");
                       Thread.sleep(500);
                   }
                   else{
                        selector.selectNow();
                                       Set Keys=selector.keys();
                                       Iterator iterator =Keys.iterator();
                        while(iterator.hasNext()){
                            SelectionKey key=(SelectionKey)iterator.next();

                            if(key.isConnectable()){
                                channel.register(selector,SelectionKey.OP_READ);
                                System.out.println("Connectable");
                                break;
                            }

                            if(key.isReadable()){
                                channel.register(selector,SelectionKey.OP_WRITE);
                                System.out.println("Readable");
                                break;
                            }

                            if(key.isWritable()){
                                channel.register(selector,SelectionKey.OP_CONNECT);
                                System.out.println("Writable");
                                break;
                            }
                            System.out.println("<<<<<<<<<>>>>>>>>>>>>");

                       }

                        Thread.sleep(1000);
                   }
                }
            }
            catch(Exception ex){
            }
        }

        public static void main(String[] args){
            new Thread(new clientEvent()).start();
        }
    }

1 个答案:

答案 0 :(得分:1)

如果你在阻塞模式下进行连接,它会在方法调用期间阻塞并完成,所以如果你随后为OP_CONNECT注册它,isConnectable()永远不会成为真。

因此,如果你必须有非阻塞连接,你的代码已经没有,那么首先将通道置于非阻塞模式,发出connect(),注册OP_CONNECT ,然后当它触发`finishConnect()返回true时,取消注册OP_CONNECT并注册其他内容,或者因为你是一个客户端更可能只是开始发送请求。

编辑:您编辑的代码在以下方面不正确:

  1. 删除Thread.sleep()
  2. finishConnect()调用移至您选择循环的isConnected()个案例。
  3. OP_CONNECT/isConnectable()触发时,取消注册 OP_CONNECT。
  4. 删除if(!connected)测试。
  5. 我上面已经说过的大部分内容。目前你是(a)给出连接时间,(b)完成它,(c)在选择循环中等待它完成,(d)永远不要注销OP_CONNECT即使你不是对此感兴趣,(e)如果没有连接,则永远不执行select(),以及(f)尝试在select()循环中查找已完成的连接。这没有任何意义。

    另一方面,如果您不介意等待连接完成内联创建它,为什么要在非阻塞模式下呢?在阻止模式下执行,然后configureBlocking(false),注册OP_READ/OP_WRITE并完全忘记OP_CONNECTisConnectable()finishConnect()