scala - Java NIO OP_WRITE 事件触发 3 次
问题描述
我正在使用 Java NIO API 来实现一个简单的非阻塞 Web 服务器。我观察到的是,OP_WRITE
每个套接字连接注册一次,会触发它三次:
while(true) {
// ...
// Handle SelectionKey.OP_ACCEPT
if (key.isAcceptable) {
val sch = key.channel.asInstanceOf[ServerSocketChannel]
val ch = sch.accept
ch.configureBlocking(false)
ch.register(this.sel, SelectionKey.OP_WRITE)
}
// Handle SelectionKey.OP_WRITE
if (key.isWritable) {
val ch = key.channel.asInstanceOf[SocketChannel]
ch.write(writeByteBuffer.duplicate())
}
}
完整代码
package zion
import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.nio.channels.{
SelectionKey,
Selector,
ServerSocketChannel,
SocketChannel
}
object HelloNIO {
val response: Array[Byte] =
HelloResponse.ok("HelloNIO.scala\n").getBytes()
val writeByteBuffer: ByteBuffer = ByteBuffer.wrap(response)
val readByteBuffer: ByteBuffer = ByteBuffer.allocateDirect(1024 * 2)
val PORT = 8081
def main(args: Array[String]): Unit = {
// Setup
val sel = Selector.open
val address = new InetSocketAddress(PORT)
val serverSocketChannel = ServerSocketChannel.open()
serverSocketChannel.socket.bind(address)
serverSocketChannel.configureBlocking(false)
serverSocketChannel.register(sel, SelectionKey.OP_ACCEPT)
new Thread(new SocketProcessor(sel)).start()
}
class SocketProcessor(val sel: Selector) extends Runnable {
override def run(): Unit = {
while (true) {
this.sel.select()
val keys = this.sel.selectedKeys
val iterator = keys.iterator
while (iterator.hasNext) {
val key = iterator.next()
// Handle SelectionKey.OP_ACCEPT
if (key.isAcceptable) {
val sch = key.channel.asInstanceOf[ServerSocketChannel]
val ch = sch.accept
ch.configureBlocking(false)
ch.register(this.sel, SelectionKey.OP_WRITE) // Registering only once
}
// Handle SelectionKey.OP_WRITE
if (key.isWritable) { // Key is writable 3 times for each HTTP request.
val ch = key.channel.asInstanceOf[SocketChannel]
ch.write(writeByteBuffer.duplicate())
}
}
iterator.remove()
}
}
}
}
解决方案
OP_WRITE 表示通道已准备好写入。从java文档复制:
“假设选择键的兴趣集在选择操作开始时包含OP_WRITE。如果选择器检测到相应的通道已准备好写入,已被远程关闭以进一步写入,或者有错误未决,那么它将添加OP_WRITE 到密钥的就绪集,并将密钥添加到其选定密钥集。”
推荐阅读
- android - onActivityResult 从未从小部件启动的活动中调用
- reactjs - Webpack-Dev-Server:编译时出错。防止重新加载。(堆栈:反应)
- wordpress - 努力在 Chrome Inspect 中查找元素 - 如何自定义?
- angular - 如何以角度5从URL(使用blob)下载图像
- node.js - node.js 中的“EIO:i/o 错误,写入”是什么,如何消除它?
- c++ - 该程序允许用户处理循环,只要用户输入一个奇数
- flutter - 将 TextField 下划线颜色更改为渐变
- python-3.x - Matplotlib:使用跟踪保存的动画
- python - TensorFlow 和 keras 得到相同的输出预测误差
- typescript - 如何在 TS 中实现接口并返回特定类型?