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

Posted

技术标签:

【中文标题】不使用 localhost 时 Java NIO Selector 不起作用【英文标题】:Java NIO Selector doesn't work when not using localhost 【发布时间】:2019-02-22 07:02:37 【问题描述】:

我一直在开发一个使用 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 的端口,也许这就是问题所在,但我真的想避免需要使用端口转发和防火墙设置。

【问题讨论】:

【参考方案1】:

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

InetSocketAddress hostAddress = new InetSocketAddress(NetworkingSettings.PORT);

【讨论】:

好的,在 localhost 上这确实有效,但是如果我想和我的朋友一起测试程序,我应该给他什么 IP 地址来尝试联系我? this 或其他地址中的那个? 是的,这个地址或相应的 IP 地址应该可以工作。 谢谢您,抱歉耽搁了,但是如果我有两台计算机在同一个网络下运行这样的服务器怎么办? (都在同一个路由器上)@Lolo

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

GATLING Rest API 测试 - java.nio.channels.ClosedChannelException: null

使用 java.nio.file.Paths 接口时缺少方案 (IllegalArgumentException)

使用 java.nio.MappedByteBuffer 时防止 OutOfMemory

Java NIO

为什么不建议使用 Java 原生 NIO?

为什么不建议使用 Java 原生 NIO?