开发者社区> 问答> 正文

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

我正在用Java阅读Doug Lea的可扩展I / O,并遵循了Basic Reactor Design示例代码。但是启动服务器后,客户端无法连接到服务器。

这是Reactor类:

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

处理程序类

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

我的想法开始服务器,然后启动服务器,印在控制台 但是在我进入telnet localhost 9000的终端,客户端连接:不会出现。

问题来源:Stack Overflow

展开
收起
montos 2020-03-22 13:59:48 919 0
1 条回答
写回答
取消 提交回答
  • 我不得不Reactor稍微更改运行方法。您必须致电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();
                }
            }
        }
    

    允许客户端连接。

    为了启用来自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();
            }
        }
    }
    

    注册Handler实例以进行读取,然后根据可读的选择键,调用该实例的run方法来处理读取。

    回答来源:Stack Overflow

    2020-03-22 14:00:44
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
如何运维千台以上游戏云服务器 立即下载
网站/服务器取证 实践与挑战 立即下载
ECS快储存加密技术 立即下载