SocketChannel 触发 isReadable() 但没有任何内容可供读取

问题描述 投票:0回答:2

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

我在

onProgressUpdate
中调用所需的函数。这是一个
WebSocket
应用程序,所以我需要发送和接收握手。发送和接收握手与此 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 循环。剩余字节永远不会得到 < 0 because there is nothing to read and bytesRead stays 0.

我的问题是,当没有什么可读的时候,为什么 isReadable 为 true?

java android sockets nio socketchannel
2个回答
2
投票

如果

bytesRead < 0
你应该关闭通道,或者至少取消注册
OP_READ
。否则你会一遍又一遍地听到
OP_READ
告诉你关于EOS的事。

您不应在每次阅读时分配一次

ByteBuffer
。分配
ByteBuffer
是一项昂贵的操作。至少为读取方法的每个条目分配一次。更好的是,当您接受它时,为每个频道分配一个。您可以将其保留为密钥附件或通过密钥附件保存,这样您就不会丢失它,并且当您取消密钥或关闭频道时它会消失。


2
投票

已读取全部的SelectionKey应从Selector返回的集合中删除。

我想这篇文章会帮助你理解。

为什么要在java nio中的`selector.selectedKeys().iterator()`中删除key?

© www.soinside.com 2019 - 2024. All rights reserved.