用JAVA 源码角度看 客户端请求服务器流程中地址是域名情况下解析域名流程

1. 域名解析的入口点

  • getaddrinfo 或 getAllByName 方法:在底层,Java 使用 getaddrinfo(在 Unix-like 系统中)或类似的系统调用来解析域名。在 Java 的 InetAddress 类中,getAllByName 方法是解析域名的入口点之一。它会调用 getAddressesFromNameService 方法来获取域名对应的 IP 地址列表。

2. getAddressesFromNameService 方法

  • 调用 nameService.lookupAllHostAddr:此方法尝试通过注册的 NameService(如 PlatformNameService)来解析域名。PlatformNameService 是一个内部类,它实现了 NameService 接口,并调用 impl.lookupAllHostAddr 方法来执行实际的域名解析。
  • 处理异常:如果解析失败,会抛出 UnknownHostException。对于 "localhost" 这样的特殊情况,会直接返回回环地址。
  • 处理请求地址:如果指定了请求地址 (reqAddr),则会检查解析结果中是否包含该地址,并进行相应的处理(如旋转数组).

3. lookupAllHostAddr 方法

  • 本地缓存和系统缓存:在某些实现中,可能会先检查本地缓存或系统缓存,以快速获取域名对应的 IP 地址。
  • 调用底层系统调用:最终,会调用底层的系统调用(如 getaddrinfo)来从 DNS 服务器获取域名对应的 IP 地址列表。这个过程可能涉及与本地 DNS 服务器的通信,以及 DNS 服务器之间的查询转发.

4. plainConnect 和 plainConnect0 方法

  • 权限检查:在 plainConnect 方法中,会先检查是否已经连接。如果未连接,则会进行权限检查,确保有权限连接到指定的 URL。
  • 使用缓存:在 plainConnect0 方法中,会尝试从本地缓存中获取响应。如果缓存命中且满足条件(如不是 HTTPS 请求),则会直接使用缓存的响应,而不需要进行实际的网络连接。
  • 代理选择:如果没有缓存命中,则会根据配置选择合适的代理(如实例代理或系统默认代理)。如果没有代理或代理连接失败,则会尝试直接连接。
  • 创建 HTTP 客户端:通过 getNewHttpClient 方法创建一个新的 HTTP 客户端,并设置连接超时和读取超时等参数。
  • 打开服务器连接:调用 openServer 方法来打开与远程服务器的连接。如果使用代理,则会通过代理服务器进行连接。

5. openServer 方法

  • 安全检查:如果存在安全管理器,则会进行连接权限检查。
  • 处理代理:如果使用代理,则会根据代理类型(如 HTTP 代理或 SOCKS 代理)进行相应的处理。对于 HTTP 代理,会调用 privilegedOpenServer 方法来通过代理服务器建立连接。
  • 直接连接:如果没有代理或代理连接失败,则会直接连接到远程服务器。调用 super.openServer 方法来执行实际的连接操作.

总结

Java 客户端请求流程中解析域名的过程涉及多个层次的处理,从 InetAddress 类的高层方法到底层的系统调用。通过缓存、代理选择和权限检查等机制,Java 能够灵活地处理各种网络环境下的域名解析和连接请求。这个过程确保了客户端能够高效、安全地与远程服务器进行通信。

##实验代码

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpUrlConnectionDemo {

    public static void main(String[] args) {
        try {
            // 创建URL对象
            URL url = new URL("http://www.baidu.com");
            // 打开连接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            // 设置请求方法为GET
            connection.setRequestMethod("GET");
            // 设置超时时间
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(5000);

            // 获取响应码
            int responseCode = connection.getResponseCode();
            System.out.println("Response Code: " + responseCode);

            // 如果响应成功,则读取响应内容
            if (responseCode == HttpURLConnection.HTTP_OK) { // 200表示成功
                BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String inputLine;
                StringBuilder content = new StringBuilder();

                while ((inputLine = in.readLine()) != null) {
                    content.append(inputLine);
                }

                // 关闭流
                in.close();
                // 输出响应内容
                System.out.println("Response Content: " + content.toString());
            } else {
                System.out.println("GET request not worked");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

##java源码

protected void plainConnect()  throws IOException {
        synchronized (this) {
            if (connected) {
                return;
            }
        }
        SocketPermission p = URLtoSocketPermission(this.url);
        if (p != null) {
            try {
                AccessController.doPrivilegedWithCombiner(
                    new PrivilegedExceptionAction<>() {
                        public Void run() throws IOException {
                            plainConnect0();
                            return null;
                        }
                    }, null, p
                );
            } catch (PrivilegedActionException e) {
                    throw (IOException) e.getException();
            }
        } else {
            // run without additional permission
            plainConnect0();
        }
    }

protected void plainConnect0()  throws IOException {
        // try to see if request can be served from local cache
        if (cacheHandler != null && getUseCaches()) {
            try {
                URI uri = ParseUtil.toURI(url);
                if (uri != null) {
                    cachedResponse = cacheHandler.get(uri, getRequestMethod(), getUserSetHeaders().getHeaders());
                    if ("https".equalsIgnoreCase(uri.getScheme())
                        && !(cachedResponse instanceof SecureCacheResponse)) {
                        cachedResponse = null;
                    }
                    if (logger.isLoggab
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值