SelectedKeys不会删除socketChannel和Selector每次都选择它

时间:2014-02-20 13:06:22

标签: java selector nio

每次选择SocketChannel可读时,我都会编写简单的echo-client和selector。 如果我尝试读取这个socketChannel,我会得到EOF。

我从selector.selectedKeys()中删除了SelectedKey。选择器的问题是什么?

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

public class Test {
    public static void main(String[] args) {
        try {
            Selector selector = Selector.open();

            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);

            socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_WRITE | SelectionKey.OP_READ);
            socketChannel.connect(new InetSocketAddress("localhost", 2000));

            System.out.println("start eventloop");

            ByteBuffer byteBuffer = ByteBuffer.wrap("echo\n".getBytes());
            int i = 0;
            while(true) {
                try{
                    if(i++==10) break;
                    selector.select();
                    System.out.println("events: " + selector.selectedKeys().size());
                    Iterator<SelectionKey> it = selector.selectedKeys().iterator();

                    while(it.hasNext()) {
                        SelectionKey selectionKey = it.next();
                        SocketChannel channel = (SocketChannel)selectionKey.channel();

                        if(selectionKey.isConnectable()) {
                            System.out.println("connectable");
                            try{
                                channel.finishConnect();
                                System.out.println("connected " + channel.getLocalAddress() + " <> " + channel.getRemoteAddress());
                            } catch (Exception e) {
                                e.printStackTrace();
                                channel.close();
                            }
                        }
                        if(selectionKey.isReadable()) {
                            System.out.println("readable");
                            ByteBuffer buffer = ByteBuffer.allocate(32);
                            buffer.clear();
                            int x = channel.read(buffer);
                            if(x > 0) {
                                buffer.flip();
                                System.out.println("server> " + Charset.defaultCharset().decode(buffer).toString());
                            } else {
                                System.out.println("EOF");
                            }
                        }
                        if(selectionKey.isWritable()) {
                            System.out.println("writeable");
                            channel.write(byteBuffer);
                            byteBuffer.flip();
                            channel.register(selector, SelectionKey.OP_READ);
                        }
                        it.remove();
                    }
                    System.out.println("not handled events:" + selector.selectedKeys().size());
                } catch (Exception e) {
                    e.printStackTrace();
                    break;
                }
            }
            selector.close();
            socketChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

STDOUT:

start eventloop
events: 1
connectable
connected /127.0.0.1:65283 <> localhost/127.0.0.1:2000
not handled events:0
events: 1
writeable
not handled events:0
events: 1
readable
server> echo

not handled events:0
events: 1
readable
EOF
not handled events:0
events: 1
readable
EOF
not handled events:0
events: 1
readable
EOF
not handled events:0
events: 1
readable
EOF
not handled events:0
events: 1
readable
EOF
not handled events:0
events: 1
readable
EOF
not handled events:0
events: 1
readable
EOF
not handled events:0

1 个答案:

答案 0 :(得分:0)

它确实删除了它,但它只是不断重现,因为OP_WRITE几乎总是准备就绪,因为套接字发送缓冲区几乎总是有空间。您只应在遇到零长度写入时注册此事件,并且应在OP_WRITE提示写入成功后立即取消注册。