1

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

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

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

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

版本 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 回答