【C语言网络编程】HTTP 客户端请求(域名解析过程)

在做 C 语言网络编程或模拟 HTTP 客户端时,第一步就离不开"把域名解析为 IP 地址 "这一步。很多人可能直接复制粘贴一段 gethostbyname 的代码,但未必真正理解它的原理。

本篇博客将围绕一个经典函数:

cpp 复制代码
char *host_to_ip(const char *hostname)

深入剖析 DNS 解析过程IP 地址转换机制,并进一步带你了解 HTTP 请求是如何基于 TCP 通信进行的。

一、核心函数:host_to_ip 是干什么的?

cpp 复制代码
char *host_to_ip(const char *hostname) {
    struct hostent *host_entry = gethostbyname(hostname);  // 1. DNS 查询
    if (host_entry) {
        return inet_ntoa(*(struct in_addr*)host_entry->h_addr_list[0]); // 2. IP 转换
    }
    return NULL;
}

这段代码的目标是:将一个域名(如 www.baidu.com)转换为对应的 IP 地址字符串(如 "14.215.177.39")

二、代码详解:每一步到底在干什么?

第一步:DNS 解析

cpp 复制代码
struct hostent *host_entry = gethostbyname(hostname);

这个函数调用了底层的 DNS 解析逻辑,流程如下:

  • 检查系统的 DNS 缓存或 /etc/hosts

  • 若无记录,则构造 DNS 请求报文,通过 UDP 协议发送到 DNS 服务器(如 114.114.114.114)

  • 等待服务器响应,返回域名对应的 IP 地址

  • 封装在 struct hostent 结构体中

第二步:IP 转换为字符串

cpp 复制代码
inet_ntoa(*(struct in_addr*)host_entry->h_addr_list[0]);

host_entry->h_addr_list[0] 是原始的 4 字节 IP 地址(网络字节序),不能直接打印。

所以我们使用 inet_ntoa() 把它转换成字符串形式:

  • 输入:一个 struct in_addr 类型的二进制 IP 地址

  • 输出:可读字符串,如 "14.215.177.39"

三、这段代码在 HTTP 请求中的位置

cpp 复制代码
[输入 URL] -> [解析域名 -> IP] -> [建立 TCP 连接] -> [发送 HTTP 请求] -> [接收响应]
                    ↑
               就在这一步!

也就是说,host_to_ip() 实际完成的是整个 HTTP 通信的第一步:获取目标服务器的 IP 地址。

如果这一步失败(如 DNS 解析失败、没有网络),后续的 socket 连接和 HTTP 请求就完全无法进行。

四、HTTP 是如何发送请求的?(基于 TCP)

HTTP 是一个应用层协议,它不能直接和服务器通信,而是借助 TCP 作为底层传输通道。流程如下:

cpp 复制代码
1. 客户端通过 DNS 得到目标 IP(host_to_ip 实现)
2. 使用 socket 与服务器 IP 的 80(HTTP)或 443(HTTPS)端口建立 TCP 三次握手连接
3. 连接成功后,发送 HTTP 请求报文
4. 服务器返回 HTTP 响应报文
5. 客户端接收、解析、展示结果

五、完整代码

cpp 复制代码
/**
 * 将主机名(域名)转换为对应的 IP 地址字符串
 * 例如:输入 "www.baidu.com",返回 "14.215.177.39"
 */
char *host_to_ip(const char *hostname) {

    // 通过 DNS 解析主机名,返回主机信息结构体指针
    struct hostent *host_entry = gethostbyname(hostname);   // gethostbyname 是阻塞式调用

    // 检查解析是否成功
    if (host_entry) {
        /**
         * host_entry->h_addr_list 是一个指针数组,存储所有解析到的 IP 地址(可能多个)
         * 每个元素是一个 struct in_addr* 类型(指向网络字节序的 IP)
         * 这里取第一个 IP(通常是优先级最高的)
         *
         * 需要将该地址强制转换为 struct in_addr*,传给 inet_ntoa 进行转换
         *
         * 注意:inet_ntoa 返回的是静态内存,不能多线程共享或多次直接使用返回值
         */
        return inet_ntoa(*(struct in_addr*)host_entry->h_addr_list[0]);
    }

    // 解析失败,返回 NULL
    return NULL;
}

https://github.com/0voice

相关推荐
白猫不黑2 小时前
从运维到网络安全:转行优势、路径与薪资前景全解析
运维·网络·web安全·网络安全·信息安全·渗透测试
dog2502 小时前
多路径聚合效率的统计理论
网络·tcp/ip
草莓熊Lotso2 小时前
【Linux网络加餐】手动部署:SSH 与 Web 服务实战 + 底层原理全解析
linux·运维·网络·人工智能·python·langchain·ssh
剑锋所指,所向披靡!2 小时前
TCP并发服务器
服务器·网络·tcp/ip
网安蟹佬霸3 小时前
密码学安全实战:从加密原理到哈希破解的完整攻防指南
网络·算法·安全·web安全·开源·密码学·哈希算法
AI备忘录3 小时前
(十一)DHCP 配置命令五厂商对照:华为 华三 锐捷 迈普 思科
服务器·网络·网络协议·网络安全·华为
迪康coolmu4 小时前
企业文件外发防泄漏实践:从通道封堵到三层全链路管控
大数据·运维·网络·人工智能·安全·阿里云
星恒讯工业路由器12 小时前
新一代通信网:从“连接万物”到“智联万物”的关键跃迁
网络·物联网·智能路由器·工业路由器·工业物联网·5g-a·新一代通信网
暴力求解13 小时前
Linux网络---传输层协议TCP(二)
linux·服务器·开发语言·网络·tcp/ip
石头猫灯13 小时前
WordPress wp2shell 漏洞链完整拆解流程
网络·数据结构·安全·web安全