8

如果客户端套接字在服务器套接字之前打开,Java 将生成ConnectionException。所以我必须检查服务器是否可用并在执行之前一直等待

socketChannel.open(hostname, port)

在客户端线程中。我找到了一个相关的 API:

InetAddress.getByName(hostname).isReachable()

但是,这仍然无法判断特定端口上的套接字是否打开。我认为这个问题应该很常见,但我没有从谷歌和其他地方得到非常有用的信息。

4

3 回答 3

14
boolean scanning=true;
while(scanning) {
    try {
        socketChannel.open(hostname, port);
        scanning=false;
    } catch(ConnectionException e) {
        System.out.println("Connect failed, waiting and trying again");
        try {
            Thread.sleep(2000);//2 seconds
        } catch(InterruptedException ie){
            ie.printStackTrace();
        }
    } 
}

这是 sonics 评论的代码

于 2013-09-04T14:46:38.863 回答
4

我将为您的客户提供这种处理程序,我在我的小游戏中使用它。

几次后它也会放弃。

private static int MAX_CONNECTION = 10;
private int reconnections = 0;

public void connect() {

            try {
                    this.socket = new Socket();
                    InetSocketAddress sa = new InetSocketAddress(this.server, this.port);
                    this.socket.connect(sa,500);
                    this.connected = true;

                    this.in = new InputStreamReader(this.socket.getInputStream());
                    this.out = new OutputStreamWriter(this.socket.getOutputStream());
            } catch (ConnectException e) {
                    System.out.println("Error while connecting. " + e.getMessage());
                    this.tryToReconnect();
            } catch (SocketTimeoutException e) {
                    System.out.println("Connection: " + e.getMessage() + ".");
                    this.tryToReconnect();
            } catch (IOException e) {
                    e.printStackTrace();
            }

    }
private void tryToReconnect() {
            this.disconnect();

            System.out.println("I will try to reconnect in 10 seconds... (" + this.reconnections + "/10)");
            try {
                    Thread.sleep(10000); //milliseconds
            } catch (InterruptedException e) {
            }

            if (this.reconnections < MAX_RECONNECTIONS) {
                    this.reconnections++;
                    this.connect();

            } else {
                    System.out.println("Reconnection failed, exeeded max reconnection tries. Shutting down.");
                    this.disconnect();
                    System.exit(0);
                    return;
            }

    }

下面是代码的解释:

private static final int MAX_CONNECTION = 10;
private int reconnections = 0;

首先我声明了两个变量,一个是固定的,不能在运行时更改,这是我希望客户端在关闭之前进行的最大尝试次数。第二个是当前的重新连接尝试。

公共方法 connect() 用于连接套接字。我将跳到异常处理:

} catch (ConnectException e) {
    System.out.println("Error while connecting. " + e.getMessage());
    this.tryToReconnect();
} catch (SocketTimeoutException e) {
    System.out.println("Connection: " + e.getMessage() + ".");
    this.tryToReconnect();
}

当抛出连接异常时,捕获器调用重新连接方法。

重新连接方法在每次尝试之间等待 10 秒,如果失败,则每次由 connect() 调用。

如果连接建立,connect() 将不会再次调用 tryToReconnect()。如果在 100 秒内无法连接,则每 10 秒尝试 10 次,则程序退出。

于 2013-09-04T15:31:56.743 回答
1

我来到这个车队寻找答案,然后我做了一个“这样怎么样”的评论。现在,分享我自己的答案似乎是公平和具有社区意识的,从我自己的工作(绿色单元测试)代码中复制并粘贴不变:

private void makeSocketWithRetries(long maxWaitMS) throws IOException {
    Stopwatch retryWatch = new Stopwatch().reset();
    final long retryWaitMS = 500;

    do {
        try {
            socket = new Socket(host, port);
        }
        catch (ConnectException e) {
            logger.info("failed to connect tp [" + host + ":" + port + "]: retrying in " + retryWaitMS + "(ms)");
            try {
                Thread.sleep(retryWaitMS);
            } catch (InterruptedException interruptedException) {
                // swallow this exception
            }
        }
    }
    while ((socket == null) && (retryWatch.mark().deltaMS() <= maxWaitMS));

    if (socket == null) {
        String msg = "failed to connect tp [" + host + ":" + port + "] total wait time exceeded: " + retryWatch.deltaMS() + "(ms)";
        logger.info(msg);
        throw new ConnectException(msg);
    }
}

这就是“说”,这里有一些注意事项:

  1. 日志记录有点多,但它显示了正在发生的事情。跟踪日志记录对重试更有意义,也可能对“超时”异常更有意义。或者只是完全丢弃日志记录。
  2. retryWait应该是一个类常量(或者一个带有验证/范围上限/ log.warning 如果非常大/等的参数)至少它是一个本地最终#8-)__
  3. 我的Stopwatch实用程序类没有显示,但它应该hopfefully 是不言而喻的。
  4. 没有参数检查,尽管负maxWaitMS 等待仍将至少进行一次尝试。

另外,我不计算(也不限制)重试次数。根据我对@Cruncher 解决方案的评论,我认为这通常不是一个有用的功能。

于 2020-12-14T16:43:42.803 回答