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

时间:2013-02-04 15:46:08

标签: java android sockets udp nio

我有使用非阻塞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.我知道服务器应用程序正在执行其工作,因为第一个代码段工作正常。我设置选择器错了吗?我猜我错过了一些步骤,但我无法弄明白。

1 个答案:

答案 0 :(得分:1)

我相信我们之前在其他主题中已经讨论过,如果第一个代码有效,第二个代码没有,那么选择器必须在Android中被破解。您的代码是正确的(只要您每次获得非零返回时清除选择器的选定键集)。您可以通过在Java平台上运行它来验证它。

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

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

注意:你没有在旋转,你在select().

中永远阻止