SocketChannel触发了isReadable()但没有可读的内容

4

我遇到了一个新的问题,涉及我的安卓应用程序。 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);
            }
        }
    }

我在onProgressUpdate中调用所需的函数。这是一个WebSocket应用程序,因此我需要发送和接收握手。使用此while循环可以发送和接收握手。首先是SelectionKey.isWriteable()和握手发送,然后是SelectionKey.isReadable()和握手读取。但是,SelectionKey.isReadable()仍然为true。现在调用普通的读取函数(而不是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循环中。remainingBytes永远不会小于0,因为没有内容可读取,而bytesRead保持为0。 我的问题是,为什么当没有内容可读取时isReadable为true?
2个回答

2
所有已读取的SelectionKey应该从Selector返回的集合中删除。 我认为这篇文章会帮助你理解。 为什么在Java NIO中`selector.selectedKeys().iterator()`中的键应该被删除?(原文链接)

1
即使我从选择集中删除了选择键,我仍然遇到同样的问题。 - Jakob Jenkov

2
如果bytesRead < 0,您应该关闭通道或至少注销OP_READ。否则,您将不断收到OP_READ来告诉您有关EOS的信息。 您不应该每次读取都分配ByteBuffer。分配ByteBuffers是一项昂贵的操作。至少在进入read方法时分配一次。更好的做法是,在接受通道时为其分配一个ByteBuffer。您可以将其保留为键附加项,以便不会丢失它,并且在取消键或关闭通道时它会消失。

抱歉我很幼稚,但是我该怎么取消OP_READ的注册? - Mayank
@Mayank 使用SelectionKey.interestOps()方法。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,