1

Web ページの読み込み中に多数のメトリックを測定する Java メソッドを実装しています。メトリクスには、解決時間、接続時間、ダウンロード時間などがあります。

コードが2 つのNS ルックアップを決してトリガーしてはならないため (DNS キャッシングが無効になっている場合でも)、課題は名前解決のようです。

私が最初に考えたのは、サーバーに接続する前に名前解決をトリガーし、接続時に Java が 2 つ目の名前解決を実行しないようにすることでした。名前のルックアップに InetAddress.getByName() を使用し、次に HttpURLConnection と setRequestProperty メソッドを使用してホストヘッダーを設定すると、うまくいくように見えました。

では、私の質問は次のとおりです。以下の 2 つのスニペットは同じ効果がありますか? 考えられるすべてのホストに対して常にまったく同じ結果が得られますか? そうでない場合、他にどのようなオプションがありますか?

バージョン 1: 暗黙の名前解決

/**
 * Site content download Test
 * 
 * @throws IOException
 */
public static void testMethod() throws IOException {

    String protocol = "http";
    String host = "stackoverflow.com";
    String file = "/";

    // create a URL object
    URL url = new URL(protocol, host, file);

    // create the connection object
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();

    // connect
    conn.connect();

    // create a stream reader
    BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String inputLine;

    // read contents and print on std out
    while ((inputLine = in.readLine()) != null) {
        System.out.println(inputLine);
    }

    // close the stream
    in.close();
}

バージョン 2: 明示的な名前解決

/**
 * Enhanced Site content download Test
 * 
 * @throws IOException
 */
public static void testMethod2() throws IOException {

    String protocol = "http";
    String host = "stackoverflow.com";
    String file = "/";

    // Do a name lookup.
    // If a literal IP address is supplied, only the validity of the address format is checked.
    InetAddress address = InetAddress.getByName(host);

    // create a URL object
    URL url = new URL(protocol, address.getHostAddress(), file);

    // create the connection object
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();

    // allow overriding Host and other restricted headers
    System.setProperty("sun.net.http.allowRestrictedHeaders", "true");

    // set the host header
    conn.setRequestProperty("Host", host);

    // connect
    conn.connect();

    // create a stream reader
    BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String inputLine;

    // read contents and print on std out
    while ((inputLine = in.readLine()) != null) {
        System.out.println(inputLine);
    }

    // close the stream
    in.close();
}

助けてくれたTIA。-ディミ

4

1 に答える 1

1

Java のソース コードを参照して、ドメイン名を HttpURLConnection に渡すとどうなるかを確認しました。最終的には次のようになりますNetworkClient.doConnect

 if (connectTimeout >= 0) {
            s.connect(new InetSocketAddress(server, port), connectTimeout);
        } else {
            if (defaultConnectTimeout > 0) {
                s.connect(new InetSocketAddress(server, port), defaultConnectTimeout);
            } else {
                s.connect(new InetSocketAddress(server, port));
            }   
        }

ご覧のとおり、ドメインの解決は常に次のように処理されInetSocketAddressます。

public InetSocketAddress(String hostname, int port) {
    if (port < 0 || port > 0xFFFF) {
        throw new IllegalArgumentException("port out of range:" + port);
    }   
    if (hostname == null) {
        throw new IllegalArgumentException("hostname can't be null");
    }   
    try {
        addr = InetAddress.getByName(hostname);
    } catch(UnknownHostException e) {
        this.hostname = hostname;
        addr = null;
    }   
    this.port = port;
}

ご覧のとおり、InetAddress.getByName毎回呼び出されます。あなたの方法は安全だと思います。

于 2012-08-07T22:00:17.467 に答える