不使用localhost时,Java NIO Selector不起作用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不使用localhost时,Java NIO Selector不起作用相关的知识,希望对你有一定的参考价值。

我一直在研究一个使用Java网络的程序,它使用this tutorial之后的NIO选择器,出于某种原因,当我尝试与我的朋友(远在另一个网络中)测试程序时,它不起作用,甚至虽然当我尝试仅在我的电脑上测试它时,它可以完美地工作。 以下是该问题的相关代码:

类EchoServer(一个线程):

private Selector selector;
private ServerSocketChannel serverSocket;
private boolean stop = false;
private List<String> pendingStrings;

public EchoServer() throws IOException {
    // Get selector
    this.selector = Selector.open();
    System.out.println("Selector open: " + selector.isOpen());
    // Get server socket channel and register with selector
    this.serverSocket = ServerSocketChannel.open();
    InetSocketAddress hostAddress = new InetSocketAddress("", NetworkingSettings.PORT);
    serverSocket.bind(hostAddress);
    serverSocket.configur eBlocking(false);
    int ops = serverSocket.validOps();
    SelectionKey selectKy = serverSocket.register(selector, ops, null);
    this.pendingStrings = new ArrayList<>();
}

@Override
public void run() {
    while (!stop) {
        try {
            update();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

private void update() throws IOException {
    System.out.println("Waiting for select...");
    int noOfKeys = selector.select();

    System.out.println("Number of selected keys: " + noOfKeys);

    Set selectedKeys = selector.selectedKeys();
    Iterator iter = selectedKeys.iterator();

    while (iter.hasNext()) {

        SelectionKey ky = (SelectionKey) iter.next();
        if (ky.isAcceptable()) {
            acceptClient();
        }
        else if (ky.isReadable()) {
            readDataFromClient(ky);
        }
        iter.remove();
    }
}

EchoClient类:

private SocketChannel client;
private InetSocketAddress hostAddress;
private boolean connected;

public EchoClient(String ip) {
    this.hostAddress = new InetSocketAddress(ip, NetworkingSettings.PORT);
    connected = false;
}

public void connect() throws IOException {
    if (!connected) {
        client = SocketChannel.open(hostAddress);
        connected = true;
    }
}

public void sendMessage(String message) throws IOException {
    try {
        byte[] messageBytes = message.getBytes();
        ByteBuffer buffer = ByteBuffer.wrap(messageBytes);
        client.write(buffer);
        buffer.clear();
    } catch (IOException e) {
        cleanUp();
    }
}

现在,似乎问题出现在服务器中,因为当我的朋友运行它时,我甚至无法连接到服务器(我是客户端)。我怀疑问题的根源是EchoServer中的那些行:

InetSocketAddress hostAddress = new InetSocketAddress("", NetworkingSettings.PORT);
serverSocket.bind(hostAddress);

但我似乎无法弄清楚它是什么。

重要说明:NetworkingSettings.PORT是80,我知道它是用于http的端口,也许这就是问题,但我真的想避免使用端口转发和防火墙设置。

答案

问题在于InetSocketAddress绑定的ServerSocketChannel。要允许localhost和远程网络接口上的连接,您需要绑定到通配符地址。这是通过使用仅接受端口号的InetSocketAddress constructor完成的:

InetSocketAddress hostAddress = new InetSocketAddress(NetworkingSettings.PORT);

以上是关于不使用localhost时,Java NIO Selector不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Java SE 8 流库

Java NIO 教程

nio

Java NIO:NIO概述

Java NIO 基本介绍

Java I/O and NIO [reproduced]