3

我有使用非阻塞 IO 来获取 UDP 数据包的工作代码,如下所示:

DatagramChannel channel = DatagramChannel.open();
channel.socket().bind(new InetSocketAddress(AUDIO_PORT));
channel.configureBlocking(false);

while(true){
   ByteBuffer packet = ByteBuffer.allocate(MAX_PACKET);
   if(channel.receive(packet) != null){
      //Got something!
      ...
   }
   ...
}

这完美无缺。现在我正在尝试做同样的事情,只是这次我想使用选择器,如下所示:

//Create a datagram channel, bind it to port, configure non-blocking:

DatagramChannel channel = DatagramChannel.open();
channel.socket().bind(new InetSocketAddress(AUDIO_PORT));
channel.configureBlocking(false);

//Create a selector and register it:

Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_READ);

//Spin

while(true){

   //If there's a packet available, fetch it:

   if(selector.selectNow() >= 1){

       //**CODE NEVER REACHES THIS POINT**

       ByteBuffer packet = ByteBuffer.allocate(MAX_PACKET);
       channel.receive(packet);
       ...
   }
   ...
}

由于我正在制作的应用程序,我真的需要它是非阻塞 IO(即使在我的示例中看起来我只是在旋转),并且用短暂的超时阻塞是行不通的。我也真的必须使用选择器。问题是,即使我有一个服务器主动向设备的 AUDIO_PORT 端口发送数据包,select() 操作总是返回 0。我知道服务器应用程序正在工作,因为第一个片段工作正常。我是否设置了选择器错误?我猜我错过了一些步骤,但我无法弄清楚。

4

1 回答 1

1

正如我相信我们之前在其他线程中讨论过的那样,如果第一个代码有效而第二个代码无效,则必须在 Android 中破坏选择器。您的代码是正确的(只要您每次获得非零返回时清除 Selector 的选定键集)。您可以通过在 Java 平台上运行它来验证这一点。

您可能会考虑更改select() == 1为以select() > 0获得更大的通用性,然后像您在所有示例中看到的那样循环选择键集,但这不应影响此代码的正确性。

我也相信我们已经讨论过,您可以尝试使用短读取超时而不是选择器的阻塞模式。

注意你不是在旋转,你是永远阻塞在select().

于 2013-02-04T23:02:21.983 回答