上下文:我最近开始在我的项目中使用java.nio
,它利用了Android的VpnService
。在我的实现中,我将FileDescriptor
的establish()
方法返回的VpnService
包装到了java.nio.FileChannel
中,如下所示。
private val outboundNetworkChannel = FileInputStream(fd).channel
之后,我有一个kotlin协程,它无限期地从
FileChannel
读取并处理出站IPv4 / IPv6数据包。问题:下面提到的代码片段有效,但是我看到
FileChannel
发生了很多空读取,这又不必要地旋转了while
循环。fun reader() = scope.launch(handler) {
while (isActive) {
val pkt = read()
if(pkt !== DUMMY){
// Send the read IPv4/IPv6 packet for processing
}
}
}
private suspend fun read(): IPDatagram =
withContext(Dispatchers.IO) {
val bytes = ByteBufferPool.acquire()
outboundChannel.read(bytes) // Returns a lot of empty reads with return value as 0
return@withContext marshal(bytes) // Read IPv4/IPv6 headers and wrap the packet
}
我正在寻找的是:事实上,我知道
FileChannel
是一个阻塞通道,在这种情况下,由于该通道由网络接口支持,因此它可能没有要读取的数据包。有/没有FileChannel
的更好方法是否可以导致更有效的实现而又不会浪费宝贵的CPU周期?我也对新想法持开放态度:) 最佳答案
在浏览VpnService
的Android文档后,我设法弄清了这一点。默认情况下,使用VpnService.Builder
建立VPN连接时,fd
处于非阻止模式。从API级别21开始,可以setBlocking(true)
。
如public VpnService.Builder setBlocking (boolean blocking)
的文档中所述
将VPN接口的文件描述符设置为
阻止/非阻止模式。默认情况下,返回文件描述符
通过Establishment()是非阻塞的。