Java Selector 在写入通道后返回带有 OP_READ 的 SelectionKey,而没有无限循环中的数据

发布于 2024-12-12 09:57:28 字数 3595 浏览 0 评论 0原文

我的代码遇到了麻烦:我用 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;

}

I've trouble with my code: i've written simple SocketChannel client with Selector, after starting it successfully reads messages from server (server sends events). But after writing to socket (see main method) selector starts returning readable socket in infinyty loop, handleKey returns that -1 bytes readed, so selector all time returns OP_READ SelectionKey without data for reading.
Sorry for my English.

Thanks.

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;

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

落叶缤纷 2024-12-19 09:57:29

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

read() returns -1 at EOS, which you are completely ignoring. When you get EOS, you must either close the channel or at least deregister interest in OP_READ. Otherwise you will just get another OP_READ and another -1 when you read, as you are doing, forever. Contrary to your comments above, read() returns zero on an empty read. You can ignore that, indeed you won't even see it if you only read when isReadable(), unless you read in a loop, but you must not ignore EOS.

蓝戈者 2024-12-19 09:57:29

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

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

这意味着您应该注销对 OP_READ 的兴趣。

read() returns -1 when it has read EOF. Definition:

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

This means you should unregister the interest for OP_READ.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文