3

我有以下代码连接到服务器,发送请求,然后返回响应。

问题是如果客户端无法连接到服务器,程序永远不会超过这个部分

PayLoad payLoadFromServer = client.sendRequest();

我只是想知道防止程序冻结的最佳方法是什么,即如果客户端无法连接,我想在 5 秒后超时,并且能够在程序中优雅地处理它。注意我不能编辑 Client 类。

public PayLoad queryServer() {
        try (final Client client = new Client("127.0.0.1", "8080")) {
            PayLoad payLoadFromServer = client.sendRequest();

            return payLoadFromServer;
        }
    }

非常感谢!

4

6 回答 6

3

您应该在类中使用java.net.Socket的connect(SocketAddress endpoint, int timeout)方法。这是最好的解决方案,但它可能存在其他解决方案。Client

于 2012-08-03T10:12:09.760 回答
1

我会在客户端代码中添加一个计时器,以便在 5 秒内未建立连接时关闭 Socket。这在外部更难做到。

于 2012-08-03T10:06:14.320 回答
1

我试着快速尝试一下。为您的客户端类创建一个包装器对象并使这个新对象可运行。

public class ClientWrapper implements Runnable {

  private final String ip;
  private final String port;
  private Client client;
  Lock lock = new ReentrantLock();

  /**
   * Creates a new instance of ClientWrapper.
   * 
   * @param ip
   * @param port
   */
  public ClientWrapper(String ip, String port) {

    this.ip = ip;
    this.port = port;
  }

  public Lock getLock() {

    return lock;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void run() {

    lock.lock();
    client = new Client(ip, port);
    lock.unlock();
  }

  //create a method to expose client or its methods. 


}

现在使用这个对象的一个​​实例作为线程,如下所示。

import java.util.concurrent.TimeUnit;

/**
 * @author rbhatt
 */
public class ClientCaller {

  public static void main(String args[]) throws InterruptedException {

    ClientWrapper clientWrapper = new ClientWrapper("127.0.0.1", "8080");

    Thread t = new Thread(clientWrapper);
    t.start();

    boolean ret = clientWrapper.getLock().tryLock(250, TimeUnit.MILLISECONDS);

    if (ret == false) {
      System.out.println("can not acquire lock in 250 milliseconds, kill the thread.");
      t.interrupt();
    } else {
      System.out.println("acquired lock in 250 milliseconds,release lock obtain client!");
      clientWrapper.getLock().unlock();
    }

  }

}

如您所见,您可以在调用者中控制您的超时,而我们无法获得锁,杀死客户端包装线程。我用过中断,可以用volatile变量。您也可以使用 aexecutor servicethread pools

注意:我编写这段代码只是为了说明这个想法,可以通过许多不同的方式改进代码。

于 2012-08-03T10:42:53.140 回答
0

如果您使用 Socket 连接到客户端,您可以提供一个 SocketFactory 并为它创建的每个 Socket 设置超时。

否则,我可能会使用两个线程。第一个做实际连接,第二个在超时后第一个触发中断。

这将需要一系列锁,一个用于防止在您尝试连接之前发生超时,一个用于等待尝试连接

于 2012-08-03T10:13:05.513 回答
0

最好使用 Timer,这里是网络操作超时的一个很好的链接。 在 Java http://www.javacoffeebreak.com/articles/network_timeouts/中处理网络超时

于 2012-08-03T10:15:54.030 回答
0

不是最好的主意,但这取决于您的项目逻辑和环境。您可以使用 ExecutorService 包装您的方法:

import java.util.concurrent.*;

private int threads = 10;

// overide thread count to prevent too many threads to be created
private ExecutorService executor = new ThreadPoolExecutor(0, threads,
        60L, TimeUnit.SECONDS,
        new SynchronousQueue<Runnable>());

// if TimeOutException isthrown - then 5 secs is out
public PayLoad sendRequest(long timeout) throws InterruptedException, ExecutionException, TimeoutException {
       return executor.submit(new Callable<PayLoad>() {
            @Override
            public PayLoad call() {
                  // your code implementation of client.sendRequest();
            }
        }).get(timeout, TimeUnit.SECONDS);
 }

我在这里使用了 10 个线程的缓存线程池。唯一不好的事情是用另一个线程包装每个方法调用。并且不要忘记关闭您的池实施。

于 2014-09-25T15:34:12.393 回答