Question

I have got a new problem with my Android app. The SocketChannel tells me that it isReadable() but there is nothing to read.

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

I call the needed functions in onProgressUpdate. It is a WebSocket app so I need to send and receive a handshake. Sending and receiving the handshake works with this while loop. First the SelectionKey.isWriteable() and the handshake is sent then the SelectionKey.isReadable() and the handshake is read. But then SelectionKey.isReadable() is still true. Now the normal read function (not the readHandshake) function is called. But there is nothing to read. Here is the code of my read function:

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

Now it gets stuck in an endless while loop. remainingBytes never gets < 0 because there is nothing to read and bytesRead stays 0.

My question is why is isReadable true when there is nothing to read?

Was it helpful?

Solution

If bytesRead < 0 you should close the channel or at least deregister OP_READ. Otherwise you will keep getting OP_READ over and over again to tell you about the EOS.

You shouldn't allocate your ByteBuffer once per read. Allocating ByteBuffers is an expensive operation. At least allocate it once per entry to the read method. Better still, allocate one per channel when you accept it. You can keep it as, or via, the key attachment so you don't lose it, and so it disappears when you cancel the key or close the channel.

OTHER TIPS

The SelectionKey which has been read all should be removed from the set returned by Selector.

I think this article would help you understand.

Why the key should be removed in `selector.selectedKeys().iterator()` in java nio?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top