【问题标题】:Select on non-blocking FileDescriptors在非阻塞 FileDescriptors 上选择
【发布时间】:2013-12-28 18:16:36
【问题描述】:

我有一个或多个非阻塞FileDescriptor 对象(已经创建并从某个子系统传递给我)。我想等待,然后使用某种 select() 从它们中读取。我如何在 Java (Android) 中执行此操作?我可以使用Selector 类吗?

【问题讨论】:

  • 你有没有找到一个好的解决方案?同样的问题(VpnService)。
  • @CamHart 从 API 级别 21 开始,Android VpnService.Builder 具有将 fd 设置为阻塞模式的选项。看看这个developer.android.com/reference/android/net/…

标签: java android io nio


【解决方案1】:

看起来我们将无法使用Selectors。

那么让我们尝试不同的方法。

假设你有一个方法open(),它返回你想要的FileDescriptor,但是阻塞了一些IO操作。您希望能够在提取 FileDescriptors 时继续开展业务,而无需等待此操作,并且您想知道它们何时准备就绪。

试试这样的:

// IMPORTS
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

class FileDescriptorFetcher extends Thread {
  final BlockingQueue<FileDescriptor> queue =
      new LinkedBlockingQueue<FileDescriptor>();
  // let's just pretend Openable provides FileDescriptors from open()
  final Openable[] from;
  boolean done;

  FileDescriptorFetcher(Openable[] fromThese) {
    from = fromThese;
    done = false;
    start();
  }

  @Override
  public void run() {
    for (Openable o : from)
      queue.offer(o.open());

    done = true;
  }

  public boolean isDone() {
    return done;
  }

  public boolean descriptorAvailable() {
    return !queue.isEmpty();
  }

  /* blocks if there are more descriptors to get and none are available,
   * returns null if all have been fetched already */
  public FileDescriptor fetchDescriptor() {
    return done
        ? null
        : queue.take();
  }
}

使用这个类,您只需在其构造函数中传递一个FileDescriptor 创建者数组,它就会开始打开它们。获取目前已经产生的所有FileDescriptors:

FileDescriptorFetcher fetcher;

// init fetcher

while (fetcher.descriptorAvailable()) {
  doStuff(fetcher.fetchDescriptor());
}

为了尽快获得每一个FileDescriptor

while (!fetcher.isDone()) {
  doStuff(fetcher.fetchDescriptor());
}

【讨论】:

  • 这就是无法从 FileDescriptor 获取 SelectableChannel 的问题。只需谷歌这个问题......我在问如何实现它来克服这个问题
  • 那么,这是一个哲学问题。为什么需要等待选择?他们实际上在阻止什么?据我所知,您不想阻止实际的FileDescriptor,它仅指已完成的打开文件操作的实际结果。正如您所说,java.nio 中的文件似乎没有任何SelectableChannels;您可能想做的是创建一个新的Thread 对象,该对象打开文件流并在工作完成时从内部列表的同步上下文中提供生成的FileDescriptors
  • 文件描述符我其实不是File System FD。我是从 VpnService 那里得到的(见 link)。所以需要用 select() 阅读它
  • 我用更通用的方法替换了我的答案。看起来怎么样?
  • 如果仍然不是这样,并且您想从它们指示的流中读取一些您根本没有描述的过程,那么您最好的选择是简单地实现 SelectableChannel您获得的 FileDescriptor 对象的包装器并将其与常规 Selector 一起使用。
【解决方案2】:

从提供的其他答案中读取 cmets,我看到您正在尝试使 VpnService fd 阻塞,这在较低的 android 版本中不支持。

我所做的是通过 JNI 代码使 fd 阻塞。希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-05
    • 1970-01-01
    • 2014-03-08
    • 1970-01-01
    • 1970-01-01
    • 2010-12-04
    • 1970-01-01
    • 2016-07-06
    相关资源
    最近更新 更多