【问题标题】:NIO Selector OP_READ and OP_WRITE, some questions about handling themNIO Selector OP_READ 和 OP_WRITE,关于处理它们的一些问题
【发布时间】:2015-02-10 08:42:01
【问题描述】:

我一直在关注this tutorial,它很有帮助,而且大多数事情都很有意义。

如果您查看第 34 页,您会看到以下 sn-p 代码:

} else if ((key.readyOps() & SelectionKey.OP_READ)
== SelectionKey.OP_READ) {
// Read the data
SocketChannel sc = (SocketChannel)key.channel();
// ...
}

这里到底发生了什么,单个 & 表示两个条件都被检查,因此,在这种情况下,key.readyOps() 将返回一个数字,其位表示可用于处理的操作。 SelectionKey.OP_READ 是另一个整数。所以我了解这两者之间的关系。
所以我脑海中的第一个测试(key.readyOps() & SelectionKey.OP_READ) 将返回truefalse。如果key.readyOps() == SelectionKey.OP_READ 是正确的,那么是真的吗?还是key.readyOps() 包含为OP_READ 设置的正确位。该特定 if 语句的开头包含相同的测试,但使用 OP_ACCEPT 而不是 OP_READ。你可以在第 33 页看到。

那么序列中的下一个测试== SelectionKey.OP_READ这里发生了什么?
在我的脑海中,我看到这样的评估:

if(true == SelectionKey.OP_READ)

if(false == SelectionKey.OP_READ)

但这不可能吧?因为 OP_READ 是一个整数?或者对于除 0 以外的任何东西,int 是否都为真?我认为这也不对,因为第二部分是多余的。

以上工作正常,我只是不清楚if 测试的实际情况。

接下来,我想知道一旦上述计算结果为true 时如何处理阅读。

首先我打电话给SocketChannel sc = (SocketChannel) key.channel(); 来获取频道的句柄。

然后我准备好缓冲区并使用int bytesRead = sc.read(myBuffer);从套接字读取

现在我需要测试读取的内容,对吗?所以我做了这样的事情:

if(read == -1){

  // The connection has been terminated, handle that. 

}else if(read == 0){

// Check data is complete, if so switch to OP_WRITE 

}else{

 // Read bytes into the buffer

}

那么以上是可以接受的吗?

javadoc 对OP_READ 进行了以下说明:

读操作的操作设置位。假设一个选择键的 兴趣集在选择操作开始时包含 OP_READ。 如果选择器检测到相应的通道已准备好 阅读,已达到流尾,已远程关闭 进一步阅读,或者有一个错误挂起,那么它将添加 OP_READ 到 键的就绪操作集,并将键添加到其选定键集。

【问题讨论】:

    标签: java bit-manipulation nio


    【解决方案1】:

    单和号表示两个条件都被检查

    这意味着计算两个操作数的按位与。由于其中一个操作数只设置了一个位,因此只检查一个条件:OP_READ.

    因此,在这种情况下,key.readyOps() 将返回一个数字,其位表示可用于处理的操作。

    当然,但是& 修改了这一点。

    SelectionKey.OP_READ 是另一个 int。所以我理解这两者之间的关系。

    以下内容不能证明您对此有信心。

    所以我脑海中的第一个测试 (key.readyOps() & SelectionKey.OP_READ) 将返回真或假。

    又错了。它将返回零或SelectionKey.OP_READ。你需要复习一下Java算术的规则。

    如果 key.readyOps() == SelectionKey.OP_READ 是正确的吗?

    没有。

    或者如果 key.readyOps() 包含为 OP_READ 设置的正确位。

    见上文。

    该特定 if 语句的开头包含相同的测试,但使用 OP_ACCEPT 而不是 OP_READ ... 那么序列中的下一个测试 == SelectionKey.OP_READ 这里发生了什么?

    首先测试OP_ACCEPT,然后测试OP_READ.

    在我的脑海中,我看到这样的评估:

    没有。往上看。你很困惑。您发布的内容没有意义。

    if(true == SelectionKey.OP_READ)

    true 不能等于整数。

    if(false == SelectionKey.OP_READ)

    同上。

    但这不可能吧?因为 OP_READ 是一个 int?

    正确。所以你想不到。

    或者对于除 0 之外的任何值,int 是否都为真?

    没有。你需要复习一下Java算术的规则。

    接下来,我想知道一旦上述评估结果为 true 时如何处理读取。

    首先我调用 SocketChannel sc = (SocketChannel) key.channel();获取频道的句柄。

    不,从SelectionKey 获取SocketChannel

    然后我准备好我的缓冲区并从套接字读取

        int bytesRead = sc.read(myBuffer);
    

    现在我需要测试读取的内容,对吗?

    你需要测试read()方法返回的结果。

    所以我做了这样的事情:

        if(read == -1){
            // The connection has been terminated, handle that. 
        }else if(read == 0){
    
        // Check data is complete
    

    没有。如果数据已经完整,你应该已经知道了,你就不会再打电话给read()了。

    // if so switch to OP_WRITE 
    

    没有。当write() 返回零时使用OP_WRITE。没有其他时间了。

    }else{
        // Read bytes into the buffer
    

    没有。字节已经在缓冲区中。

    那么以上是可以接受的吗?

    它开始没有意义。您需要再好好看看您引用的 IBM 教程。您在此处发布的误解不会出现在此处。

    【讨论】:

    • 好的,谢谢,所以我现在已经对算术进行了排序,if(key.readyOps() & SelectionKey.OP_ACCEPT) 进行按位掩码,然后检查它是否与 OP_ACCEPT 匹配。对于对sc.read(myBuffer) 的调用,这意味着我根本不需要检查read == 0
    • 正确,但您确实需要检查 form-1,如果收到则关闭频道,否则会抛出 IOException。注意取消密钥是不够的。
    • 谢谢,我想我现在可以控制一切了。感谢您的帮助。
    猜你喜欢
    • 2015-09-08
    • 1970-01-01
    • 2022-01-19
    • 2011-09-25
    • 2010-12-10
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多