Использование селектора на SocketChannel - PullRequest
1 голос
/ 18 октября 2019

Я пытаюсь дождаться чтения данных на нескольких каналах сокетов. Я скопировал пример кода из Интернета, но он не работает для меня. Проблема состоит в том, что вызов «select» правильно блокируется до тех пор, пока не будут получены первые данные, но после этого сразу же возвращает 0 (не готов). Мой код (для одного канала) выглядит следующим образом.

    final String HOST = "<REDACTED>.com";
    final int PORT    = 2000;
    SocketChannel MyChannel;
    Selector MySelector;

    void doSelect()
    {
        SelectionKey key;
        int nready;
        long nr;

        try {
            ByteBuffer bytebuf = ByteBuffer.allocate( 1024 );              // allocate bytebuffer
            InetSocketAddress addr = new InetSocketAddress( HOST, PORT);          // form addr
            MyChannel = SocketChannel.open();                   // create socketchan
            MyChannel.connect( addr );                           // connect to data src
            while( !MyChannel.finishConnect() ) Thread.sleep( 1000 ); // wait til connected
            MyChannel.configureBlocking( false );               // set non-blocking
            MySelector = Selector.open();                       // open new selector
            key = MyChannel.register( MySelector, SelectionKey.OP_READ ); // register for reads

            while( true ) {                                     // loop forever
                nready = MySelector.select();                   // block til something ready
                if( nready <= 0 ) {                             // nothing ready?
                    logit( "not ready: select returned "+nready );
                    MyChannel.close();
                    break;                                      // give up
                }
                if( key.isReadable() ) {                        // readable?
                    nr = MyChannel.read( bytebuf );             // read data
                    logit( "read "+nr+" bytes" );
                }
            }   // end while
        }   // end try
        catch( Exception e ) {
            logit( "doSelect: "+e );
            return;
        }
    }

    //@ Log a message to logcat
    void logit(String msg) { Log.i( "MYAPP", msg ); }

ОБНОВЛЕНИЕ 19.10.2009

Основываясь на предложении @ user207421, я изменил код для итерации по выбранному ключу. Это не имеет значения. Вызов select () все еще не блокирует после первого приема, и чтение из канала говорит, что прочитано 0 байт ..

Выдержка из нового кода (некоторые переменные переименованы для (my)удобочитаемость)

    while( true ) {                                     // loop forever
        nready = selector.select();                   // call select: block til something ready
        if( nready <= 0 ) {                             // nothing ready? (should never happen)
            break;                                      // give up
        }

        // PROCESS ALL SELECTED KEYS
        Set<SelectionKey> selected  = selector.selectedKeys();  // get selected key set
        Iterator<SelectionKey> iter = selected.iterator();    // create iterator
        while( iter.hasNext() ) {                             // while has more
            key = iter.next();                                // get next key
            if( key.isReadable() ) {                           // check if ready to read
                nr = chan.read( bb );                          // read from channel
                if( nr > 0 ) {                                 // got some data?
                  printByteBuffer( bb );
                }
                else {
                  // should never happen! (but it does)
                }
            }
            else if( key.isWritable()) {}                       // never happens!
            else if( key.isAcceptable()) {}                     // never happens!
            else if( key.isConnectable()) {}                    // never happens!
            iter.remove();
        }  // end while hasnext
    }   // end while  

   //@ Convert ByteBuffer to byte array and print
    void printByteBuffer(
      ByteBuffer bb )                       // BB to print
    {
        int nrem;
        byte[] bytes;
        String str;

        bb.flip();                         // reset position
        nrem = bb.remaining();
        bytes = new byte[nrem];            // alloc byte array
        bb.get( bytes );                   // get bytes from bytebuf
        str = new String( bytes );         // cnvt to string
        log( "received \""+str+"\"" );
    }  

Любые предложения с благодарностью.

1 Ответ

0 голосов
/ 21 октября 2019

Я нашел решение на основе комментария. Видимо, ByteBuffer был "полным". Я исправил проблему, выполнив команду «.clear ()» непосредственно перед чтением канала ().

Я не понимаю, почему это было необходимо, потому что ByteBuffer был намного больше (1000 байт), чем любые полученные данные, но тем не менее это работает.

Re: режим блокировки: Каждый пример, который я нашел в Интернете, говорит, что канал должен быть установлен как неблокирующий, чтобы Selector select () работал правильно. В любом случае, я вкратце попробовал режим блокировки, но не обрадовался этому.

...