如何使用Selector对象结合DatagramChannel进行非阻塞数据包接收

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。我知道服务器应用程序正在工作,因为第一个代码片段运行良好。我设置选择器的方式错了吗?我猜我漏掉了一些步骤,但我就是想不出来。

答案在这里:https://stackoverflow.com/questions/2135525/why-does-a-selectionkey-registered-to-a-datagramchannel-return-a-selectablechann - bilgin
1个回答

1

我认为我们之前在其他帖子中讨论过,如果第一个代码可行而第二个不可行,则选择器必须在Android上出现故障。您的代码是正确的(只要每次获得非零返回时清除选择器的选定密钥集)。您可以通过在Java平台上运行它来验证。

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

正如我所认为我们已经讨论过的那样,您可以尝试使用短读取超时的阻塞模式代替Selector。

NB:您没有自旋,您永远在select()中阻塞。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接