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

早速やってみました。クライアント クラスのラッパー オブジェクトを作成し、この新しいオブジェクトを実行可能にします。

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変数を使用できます。executor servicethread poolsなども使えます。

注: このコードはアイデアの説明として書いたもので、さまざまな方法でコードを改善できます。

于 2012-08-03T10:42:53.140 に答える
1

接続が 5 秒以内に確立されない場合にソケットが閉じられるように、クライアント コードにタイマーを追加します。これを外部で行うのははるかに困難です。

于 2012-08-03T10:06:14.320 に答える
0

タイマーを使用することをお勧めします。これは、ネットワーク操作のタイムアウトに関する適切なリンクです。 Java でのネットワーク タイムアウトの処理 http://www.javacoffeebreak.com/articles/network_timeouts/

于 2012-08-03T10:15:54.030 に答える
0

Socket を使用してクライアントに接続する場合は、SocketFactory を指定して、作成する各 Socket のタイムアウトを設定できます。

そうでなければ、おそらく 2 つのスレッドを使用するでしょう。最初に実際の接続を行い、2 番目にタイムアウト後に最初に割り込みをトリガーします。

これには一連のロックが必要です。1 つは接続を試行する前にタイムアウトが発生するのを防ぐため、もう 1 つは試行を待機するためです。

于 2012-08-03T10:13:05.513 に答える
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 に答える