0

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

无论如何,我的问题是:在初始化连接时,我将操作注册为连接操作(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();
        }
    }
4

1 回答 1

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)测试。

大部分我已经在上面说过了。目前,您正在 (a) 给连接时间来完成,(b) 完成它,(c) 在选择循环中等待它完成,(d)OP_CONNECT即使您不再对它感兴趣,也永远不会取消注册, (e) 如果没有连接,则永远不要执行 select(),以及 (f) 尝试在 select() 循环中查找已完成的连接。这没有任何意义。

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

于 2012-05-10T11:17:17.710 回答