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

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

现在,当我在选择器的选定键之间进行迭代时,我希望它进入可连接的控制语句,并按照控制语句中的说明更改操作。

不幸的是,我没有任何选定的键。我哪里出问题了?

        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();
        }
    }

最佳答案

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

因此,如果您必须具有非阻塞连接(代码已在其中执行此操作),请首先将通道置于非阻塞模式,发出connect(),注册OP_CONNECT,然后在触发时,`finishConnect()返回true ,取消注册OP_CONNECT并注册其他内容,或者如果您是客户端,则很可能只是开始发送请求。

编辑:通过以下方式,您编辑的代码不正确:


删除Thread.sleep()
finishConnect()调用移到选择循环的isConnected()情况下。
OP_CONNECT/isConnectable()触发时,注销OP_CONNECT。
删除if(!connected)测试。


我上面已经说过大部分。目前,您是(a)给予完成连接的时间,(b)完成连接,(c)在选择循环中等待其完成,(d)即使您不感兴趣,也不要注销OP_CONNECT (e)如果没有连接,则从不执行select();(f)尝试在select()循环中查找完整的连接。这根本没有任何意义。

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

10-04 23:04
查看更多