【问题标题】:Try to bind to a port, if it fails choose another尝试绑定一个端口,如果失败选择另一个
【发布时间】:2015-02-25 04:36:22
【问题描述】:

我正在编写一个点对点应用程序。我有一个应用程序要绑定到的默认端口。 但如果这失败了,我希望我的应用程序绑定到另一个开放端口。

我对此有一个解决方案,但我认为这不是一个非常出色的解决方案。

我在想这样的事情:

    package de.oompf.netwrk;

    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetSocketAddress;
    import java.net.SocketException;

    class Server implements Runnable {
        private final Thread serverThread;
        private final DatagramSocket socket;

        Server() throws SocketException {
            serverThread = new Thread(this, "Server Thread");
            socket = new DatagramSocket(null);
            socket.setSoTimeout(2400);

            for(int port : Configuration.getPortList()) {
                if(!socket.isBound()) {
                    try {
                        socket.bind(new InetSocketAddress(port));
                        break;
                    } catch(SocketException e) {
                    }
                } else {
                    break;
                }
            }

            if(!socket.isBound()) {
                socket.bind(new InetSocketAddress(0));
            }
        }

        void start() {
            serverThread.start();
        }

        void stop() {
            serverThread.interrupt();
            socket.close();
        }

        @Override
        public void run() {
            DatagramPacket p = new DatagramPacket(new byte[4096], 4096);
            while(!serverThread.isInterrupted()) {
                try {
                    socket.receive(p);
                } catch (IOException e) {
                    if(socket.isClosed()) {
                        break;
                    }
                }
            }
        }

    }

但是在第一次尝试将其绑定到端口失败后,套接字会关闭。

那么在 Java 中最优雅的方法是什么?

【问题讨论】:

  • 我前段时间做过同样的事情,我通过创建一个 PortScanning 方法解决了这个问题,该方法返回下一个可用端口的值。然后我将该端口传递给我的连接线程
  • 无论绑定成功与否,你的for 循环总是被中断(break;)。
  • 不,不是。有两个'break'语句。第一个仅在 bind() 成功时执行。
  • 这里有一个类似的问题,有很多有用的答案:stackoverflow.com/questions/2675362/…
  • 为什么不绑定到端口0,让操作系统为您选择正确的端口

标签: java


【解决方案1】:

解决方案是为您需要测试的每个端口创建一个新套接字。您的问题是您已将套接字字段声明为 final。所以解决方案是创建一个局部变量来存储套接字,直到你确定你有一个成功绑定的套接字或将套接字的创建委托给另一个方法。

DatagramSocket socket = null;
for (int port : Configuration.getPortList()) {
    try {
        socket = new DatagramSocket(port);
        break;
    } catch (SocketException ignored) {
        continue;
    }
}
if (socket == null) {
    socket = new DatagramSocket(0); 
}
this.socket = socket;

Server() throws SocketException {
    serverThread = new Thread(this, "Server Thread");
    socket = getBoundSocket();
    socket.setSoTimeout(2400);
}

private static DatagramSocket getBoundSocket() throws SocketException {
    for (int port : Configuration.getPortList()) {
        try {
            return new DatagramSocket(port);
        } catch (SocketException ignored) {
            continue;
        }
    }
    return new DatagramSocket(0); 
}

【讨论】:

  • 谢谢!第一个解决方案就是我所说的“我有一个解决方案”。但是第二种方法是最好的方法,到目前为止我已经看到了。
【解决方案2】:

试试这个

       for(int port : Configuration.getPortList()) {
            if(!socket.isBound()) {
                try {
                    socket.bind(new InetSocketAddress(port));
                    break;
                } catch(Exception e) {
                }
            } 
        }


    }

【讨论】:

  • 正如我所说,这行不通。当 bind() 失败时,套接字会关闭。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-08
  • 1970-01-01
  • 2014-02-21
  • 1970-01-01
  • 2020-01-26
相关资源
最近更新 更多