4

我的代码有问题:我用 Selector 编写了简单的 SocketChannel 客户端,在成功启动它之后从服务器读取消息(服务器发送事件)。但是在写入套接字(参见 main 方法)后,选择器开始在无限循环中返回可读套接字,handleKey 返回已读取的 -1 字节,因此选择器始终返回 OP_READ SelectionKey 而没有读取数据。对不起我的英语不好。

谢谢。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
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.util.Iterator;

public class SelectorTest
{

    public SelectorTest() throws IOException {
        selector = Selector.open();
    }

    private void runSelector() {

        new Thread(new Runnable() {

            public void run()
            {

                alive = true;
                try {
                    while(alive) {
                        System.out.println("Selector started...");

                        selector.select();

                        Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();

                        while(keyIter.hasNext()) {

                            SelectionKey key = keyIter.next();

                            keyIter.remove();

                            handleKey(key);
                        }
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }).start();
    }

    private void handleKey(SelectionKey key) throws IOException {

        SocketChannel chan = (SocketChannel) key.channel();
        System.out.println("Processing selected...");

        if(key.isConnectable()) {
            System.out.println("Connecting ...");
            if(chan.finishConnect()) {
                key.interestOps(SelectionKey.OP_READ);
            } else {
                key.channel();
            }
        } else if(key.isReadable()) {
            System.out.println("Processing reading...");

            ByteBuffer buf = ByteBuffer.allocate(1024);
            int readedBytes = chan.read(buf);
            System.out.println("Readed: " + readedBytes);
            buf.flip();

            for(byte b : buf.array()) {
                System.out.print((char) b);
            }
        } else if(key.isWritable()) {
            System.out.println("Finishing writing...");

            key.interestOps(SelectionKey.OP_READ);
        }
    }

    public static void main(String[] args) throws IOException {

        SocketChannel channel = SocketChannel.open();
        channel.configureBlocking(false);
        channel.connect(new InetSocketAddress("t1.sis.lan", 6001));

        SelectorTest ds = new SelectorTest();
        ds.runSelector();

        channel.register(ds.selector, SelectionKey.OP_CONNECT);

        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

        for(;;) {

            String line = in.readLine();
            if(line==null) break;

            if(line.toLowerCase().equals("bye")) break;

            if (line.toLowerCase().equals("write")) {
                String command = "GET_STREAMS\r\n\0";

                ByteBuffer buf = ByteBuffer.allocate(1024);
                buf.put(command.getBytes());
                buf.flip();

                channel.write(buf);
            }

            System.out.println("echo: "+line); // is it alive check
        }

        ds.alive = false;
        ds.selector.wakeup();
        channel.close();
    }

    private Selector selector;
    private boolean alive;

}
4

2 回答 2

6

read()在 EOS 返回 -1,你完全忽略了它。当您获得 EOS 时,您必须关闭通道或至少取消注册对 OP_READ 的兴趣。否则,当你阅读时,你只会得到另一个 OP_READ 和另一个 -1,就像你正在做的那样,永远。与您上面的评论相反,在空读取时read()返回零。你可以忽略它,实际上如果你只阅读 when 甚至看不到它isReadable(),除非你循环阅读,但你不能忽略 EOS。

于 2011-10-30T02:32:27.853 回答
0

read() 在读取 EOF 时返回 -1。定义:

read() returns: The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream

这意味着您应该取消注册 OP_READ 的兴趣。

于 2011-10-29T09:55:20.557 回答