2008-10-15 23 views
7

Khi viết một số mã kiểm tra tôi đã tìm thấy rằng Selector.select() có thể trở lại mà không có Selector.selectedKeys() chứa bất kỳ khóa nào để xử lý. Điều này xảy ra trong vòng lặp chặt chẽ khi tôi đăng ký kênh chấp nhận() ed vớiJava NIO chọn() trả về mà không có các phím được chọn - tại sao?

SelectionKey.OP_READ | SelectionKey.OP_CONNECT

làm hoạt động quan tâm.

Theo tài liệu, chọn() phải trả lại khi:

1) Có các kênh có thể hoạt động.

2) Bạn gọi rõ ràng là Selector.wakeup() - không có phím nào được chọn.

3) Bạn rõ ràng Thread.interrupt() chuỗi làm việc chọn() - không có phím nào được chọn.

Nếu tôi không nhận được khóa nào sau khi chọn() Tôi phải ở trong các trường hợp (2) và (3). Tuy nhiên, mã của tôi không gọi wakeup() hoặc ngắt() để bắt đầu các khoản trả về này.

Bất kỳ ý tưởng nào về những gì đang gây ra hành vi này?

Trả lời

9

Câu trả lời ngắn: xóa OP_CONNECT từ danh sách các thao tác bạn quan tâm cho kết nối được chấp nhận - kết nối được chấp nhận đã được kết nối.

tôi quản lý để tạo lại vấn đề, mà có thể được chính xác những gì đang xảy ra với bạn:

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()); 
    } 
} 

Sau khi máy chủ trên nhận được một kết nối, đầu tiên select() trên các lối ra kết nối mà không cần chặn và không có phím với các hoạt động sẵn sàng. Tôi không biết tại sao Java cư xử theo cách này, nhưng dường như nhiều người bị hành vi này cắn.

Kết quả tương tự trên JVM của Sun 1.5.0_06 trên Windows XP cũng như JVM của Sun 1.5.0_05 và 1.4.2_04 trên Linux 2.6.

+0

Cảm ơn câu trả lời. Điều này rõ ràng là một điều bất thường trong hành vi lựa chọn, nhưng nó dễ dàng giải quyết được. –

+0

@FrankTaylor Tôi không biết tại sao lỗi lập trình nên được coi là "một bất thường trong hành vi chọn". – EJP

9

Lý do là OP_CONNECTOP_WRITE là những điều tương tự dưới mui xe, vì vậy bạn không bao giờ nên được đăng ký cho cả hai cùng một lúc (như trên OP_ACCEPTOP_READ), và bạn không bao giờ nên được đăng ký OP_CONNECT ở tất cả khi kênh đã kết nối, như trong trường hợp này, đã được chấp nhận.

OP_WRITE hầu như luôn sẵn sàng, ngoại trừ khi bộ đệm gửi bộ đệm trong hạt nhân điện tử đã đầy, vì vậy bạn chỉ nên đăng ký sau khi bạn ghi được độ dài bằng không. Vì vậy, bằng cách đăng ký kênh đã kết nối cho OP_CONNECT,, bạn đã thực sự đăng ký OP_WRITE, đã sẵn sàng, vì vậy select() đã được kích hoạt.

Các vấn đề liên quan