简体   繁体   English

为什么在这个java nio程序中客户端无法连接到服务器?

[英]Why client can't connect to server in this java nio program?

I'm reading Doug Lea's Scalable I/O in Java , and I followed the Basic Reactor Design example code.我正在阅读 Doug Lea's Scalable I/O in Java ,并且我遵循了Basic Reactor Design示例代码。 But after I started server, the client can't connect to server.但是在我启动服务器后,客户端无法连接到服务器。

Here is the Reactor class:这是反应器类:

class Reactor implements Runnable {

    private static final Logger logger = LogManager.getLogger();

    final Selector selector;
    final ServerSocketChannel serverSocket;

    public Reactor(int port) throws IOException {
        selector = Selector.open();
        serverSocket = ServerSocketChannel.open();
        serverSocket.bind(new InetSocketAddress(port));
        serverSocket.configureBlocking(false);
        SelectionKey sk = serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        sk.attach(new Acceptor());
        logger.info("server started.");
    }

    @Override
    public void run() {
        while (!Thread.interrupted()) {
            for (final Iterator<SelectionKey> it = selector.selectedKeys().iterator(); it.hasNext(); it.remove()) {
                dispatch(it.next());
            }
        }
    }

    private void dispatch(SelectionKey key) {
        Runnable r = (Runnable) key.attachment();
        if (r != null) {
            r.run();
        }
    }

    private final class Acceptor implements Runnable {
        @Override
        public void run() {
            try {
                SocketChannel c = serverSocket.accept();
                if (c != null) {
                    new Handler(selector, c);
                }
            } catch (IOException ex) {
                ex.getMessage();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        new Reactor(9000).run();
    }
}

Handler class处理程序类

final class Handler implements Runnable {
    private static final Logger logger = LogManager.getLogger();

    final SocketChannel c;
    final SelectionKey key;
    ByteBuffer buffer = ByteBuffer.allocate(1024);

    public Handler(Selector sel, SocketChannel c) throws IOException {
        this.c = c;
        c.configureBlocking(false);
        key = c.register(sel, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
        logger.info("client connected: " + c);
    }

    void read() throws IOException {
        if (!buffer.hasRemaining()) {
            return;
        }
        c.read(buffer);
    }

    void process() {/* */}

    void write() throws IOException {
        buffer.flip();
        c.write(buffer);
        c.close();
    }

    @Override
    public void run() {
        try {
            read();
            process();
            write();
        } catch (IOException ex) {
            ex.getMessage();
        }
    }
}

I start server in idea and then server started is printed in console我在idea中启动服务器,然后在控制台中打印服务器启动
But after I enter telnet localhost 9000 in terminal, client connected: doesn't appear.但是当我在终端中输入telnet localhost 9000后, client connected:没有出现。

I had to change the Reactor run method a bit.我不得不稍微改变Reactor run 方法。 you have to call selector.select() or selector.selectNow() :你必须调用selector.select()selector.selectNow()

    @Override
    public void run() {
        while (!Thread.interrupted()) {
            try {
                int ready = selector.selectNow();
                if (ready == 0){
                    continue;
                }

                Set<SelectionKey> selected = selector.selectedKeys();
                Iterator<SelectionKey> it = selected.iterator();
                while (it.hasNext()) {
                    SelectionKey key = it.next();
                    if(key.isAcceptable() || key.isReadable()) {
                        dispatch(key);
                    }                   
                }
                selected.clear();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

that allowed the client to connect.允许客户端连接。

in order to enable an echo service from Handler I implemented this:为了从Handler启用回声服务,我实现了这个:

final class Handler implements Runnable {
    private static final Logger logger = LogManager.getLogger();
    final SocketChannel c;
    final SelectionKey key;
    ByteBuffer buffer = ByteBuffer.allocate(1024);

    public Handler(Selector selector, SocketChannel c) throws IOException {
        this.c = c;
        c.configureBlocking(false);
        logger.info("client connected: " + c);

        key = c.register(selector, 0);
        key.attach(this);
        key.interestOps(SelectionKey.OP_READ);
        selector.wakeup();
    }


    @Override
    public void run() {
        try {
            SocketChannel client = (SocketChannel) key.channel();
            client.read(buffer);
            if (new String(buffer.array()).trim().equals("close")) {
                client.close();
                System.out.println("close connection");
            }

            buffer.flip();
            client.write(buffer);
            buffer.clear();
        } catch (IOException ex) {
            ex.getMessage();
        }
    }
}

register the Handler instance for reading and then upon a readable selection key the run method of this instance is called to handle the reading.注册用于读取的Handler实例,然后根据可读的选择键调用该实例的 run 方法来处理读取。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM