【问题标题】:Effective measurement of dns lookup and site content download duration有效测量 dns 查找和站点内容下载持续时间
【发布时间】:2012-08-07 19:31:46
【问题描述】:

我正在实现一个 Java 方法,该方法在加载网页时测量多个指标。指标包括:解析时间、连接时间和下载时间。

挑战似乎在于名称解析,因为代码不应该以任何方式触发 两个 NS 查找(即使禁用 DNS 缓存)。

我的第一个想法是在连接到服务器之前触发名称解析,然后阻止 java 在连接时运行第二个。 使用 InetAddress.getByName() 进行名称查找,然后使用 HttpURLConnection 和 setRequestProperty 方法来设置 主机标头 似乎可以解决问题。

所以这是我的问题:下面这两个 sn-ps 是否具有相同的效果?他们总是对所有可能的主机给出完全相同的结果吗?如果没有,我还有什么其他选择?

版本 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 的帮助。 -迪米

【问题讨论】:

    标签: java http dns


    【解决方案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 每次都会被调用。我认为你的方法是安全的。

    【讨论】:

    • 所以基本上我们可以声称 HttpClient 类,当它获取主机名而不是 IP 地址时,与我的第二种方法的行为相似,因此没有真正的区别。我自己也查看了openjdk的源代码,我认为你说的是​​真的。我会再等一会儿,看看有没有异议,然后接受你的回答。感谢您对此进行调查。
    • 我创建了一个测试方法,测试使用这两种方法从 20 个网站中抽取样本,对于那些在每次页面加载时不更改其内容的网站,结果是相同的。我还针对本地 apache 服务器对其进行了测试,并且接收到的标头是相同的。我接受你的回答,因为它验证了我的观察。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-04
    相关资源
    最近更新 更多