4

Android アプリで新たな問題が発生しました。はそれSocketChannelを教えてくれますisReadable()が、読むものは何もありません。

while(running)
    {
        int readyChannels = 0;
        try {
            readyChannels = selector.select();
        } catch (IOException e) {
            e.printStackTrace();
        }

        if(readyChannels == 0) continue;

        Set<SelectionKey> selectedKeys = selector.selectedKeys();
        Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

        while(keyIterator.hasNext())
        {
            SelectionKey key1 = keyIterator.next();

            if(key1.isReadable())
            {
                publishProgress(1);
            }

            else if(key1.isWritable())
            {
                publishProgress(2);
            }

            else if(!key1.isValid())
            {
                Log.e("State", "progress error");
                publishProgress(3);
            }
        }
    }

で必要な関数を呼び出しますonProgressUpdateWebSocketアプリなのでハンドシェイクを送受信する必要があります。ハンドシェイクの送受信は、この while ループで動作します。最初にSelectionKey.isWriteable()と ハンドシェイクが送信され、次にSelectionKey.isReadable()と ハンドシェイクが読み取られます。しかし、それSelectionKey.isReadable()はまだ真実です。ここで、通常の読み取り関数 ( ではないreadHandshake) 関数が呼び出されます。しかし、読むべきものは何もありません。私の読み取り関数のコードは次のとおりです。

public byte[] read(int nBytes)
{
    Log.e("State", "public byte[] read(int nBytes) start");

    byte[] resultData = new byte[1024];
    ByteBuffer data = ByteBuffer.wrap(resultData);
    int remainingBytes = nBytes;

    while(remainingBytes >= 0)
    {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int bytesRead = 0;
        try {
            bytesRead = channel.read(buffer);
        } catch (IOException e) {
            Log.e("ERROR", "channel read");
        }

        if(bytesRead < 0)
        {
            sockState = WebSocketState.WebSocketErrorOccurred;
        }

        else
        {
            remainingBytes = remainingBytes - bytesRead;
            data.put(buffer.array(), 0, bytesRead);
        }
    }

    Log.e("State", "public byte[] read(int nBytes) done");

    return resultData;
}

今度は、無限の while ループに陥ります。読み取るものがなく、bytesRead が 0 のままであるため、remainingBytes が < 0 になることはありません。

私の質問は、読むものが何もないのに isReadable が真なのはなぜですか?

4

2 に答える 2

2

bytesRead <0の場合は、チャネルを閉じるか、少なくともOP_READの登録を解除する必要があります。それ以外の場合は、EOSについて通知するためにOP_READを何度も取得し続けます。

読み取りごとに1回ByteBufferを割り当てないでください。ByteBufferの割り当ては、コストのかかる操作です。少なくとも、エントリごとに1回readメソッドに割り当てます。さらに良いことに、受け入れるときにチャネルごとに1つ割り当てます。キーアタッチメントとして、またはキーアタッチメントを介して保持できるため、紛失しないようにできます。キーをキャンセルするか、チャネルを閉じると、キーアタッチメントは消えます。

于 2010-11-10T01:24:10.233 に答える
2

すべて読み取られた SelectionKey は、Selector によって返されるセットから削除する必要があります。

この記事が理解の助けになると思います。

java nioの`selector.selectedKeys().iterator()`でキーを削除する必要があるのはなぜですか?

于 2014-05-12T02:41:15.513 に答える