2008-10-15 15 views
7

Bazı test kodları yazarken, Selector.select() işleminin işlemek için herhangi bir anahtar içermeyen Selector.selectedKeys() olmadan dönebileceğini buldum. Ben ilgi operasyonlar gibiJava NIO select(), seçili tuşlar olmadan döner - neden?

SelectionKey.OP_READ | SelectionKey.OP_CONNECT

ile accept() ed kanalını kayıt olduğunda bu sıkı bir döngü içinde gerçekleşiyor.

Docs göre seçin() ne zaman dönmelidir:

1) üzerine hareket olabilir kanallar vardır.

2) Açıkça Selector.wakeup() çağrısı - hiçbir anahtar seçilir.

3) Açıkça Thread.interrupt() select yapıyor iplik() - hiçbir anahtar seçilir.

select sonra hiç anahtarları alırsanız() Ben durumlarda olmalı (2) ve (3). Ancak, kodum bu dönüşleri başlatmak için wakeup() veya interrupt() çağırmıyor.

bu davranışa neden olan ne olduğu herhangi bir fikir?

cevap

9

Kısa cevap: Kabul bağlantı için ilgilenen operasyonların listeden OP_CONNECT kaldırmak - Kabul edilen bir bağlantısı zaten bağlı.

ben tam size oluyor ne olabileceğini sorunu yeniden oluşturmak başardı: Yukarıdaki sunucu engellemeden bir bağlantı, bağlantı çıkışlarına select() ilk aldıktan sonra

import java.net.*; 
import java.nio.channels.*; 


public class MyNioServer { 
    public static void main(String[] params) throws Exception { 
    final ServerSocketChannel serverChannel = ServerSocketChannel.open(); 
    serverChannel.configureBlocking(true); 
    serverChannel.socket().bind(new InetSocketAddress("localhost", 12345)); 
    System.out.println("Listening for incoming connections"); 
    final SocketChannel clientChannel = serverChannel.accept(); 
    System.out.println("Accepted connection: " + clientChannel); 


    final Selector selector = Selector.open(); 
    clientChannel.configureBlocking(false); 
    final SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_CONNECT); 
    System.out.println("Selecting..."); 
    System.out.println(selector.select()); 
    System.out.println(selector.selectedKeys().size()); 
    System.out.println(clientKey.readyOps()); 
    } 
} 

ve hiçbir anahtar vardır Hazır operasyonlarla. Java'nın neden bu şekilde davrandığını bilmiyorum, ancak bu davranışla birçok insan ısırılmış gibi görünüyor.

sonuç Sun'ın Windows XP üzerinde JVM 1.5.0_06 yanı sıra Sun JVM 1.5.0_05 ve 1.4.2_04 Linux 2.6 üzerinde aynıdır.

+0

Cevabınız için teşekkürler. Bu açıkça seçmenin davranışında bir anormalliktir, ancak kolayca çözülebilir. –

+0

@FrankTaylor Bir programlama hatasının neden 'seçim davranışında bir anormallik' olarak görülmesi gerektiğini bilmiyorum. – EJP

9

nedeni hem aynı anda (ditto OP_ACCEPT ve OP_READ) kayıtlı asla böylece OP_CONNECT ve OP_WRITE, kaputun altında aynı şey olduğudur, ve kanal zaten hiç zaman OP_CONNECT kayıt asla Bu durumda olduğu gibi, kabul edilmişti.

Ve OP_WRITE hemen hemen her zaman hazırdır, çipte yuva gönderme arabelleği dolduğunda hariç, bu yüzden yalnızca sıfır uzunluğundaki bir yazmayı aldıktan sonra bunun için kaydetmelisiniz. Bu yüzden OP_CONNECT, için zaten bağlı olan kanalı kaydederek, hazır olan OP_WRITE,'a kayıt oldunuz, böylece select() tetiklendi.