域名解析实例(gethostbyname&&inet_ntop)

本文详细介绍了如何使用gethostbyname函数获取域名对应的主机信息,包括主机名、别名、IP地址类型及地址本身,并通过inet_ntop函数将IP地址从网络字节序转换为主机字节序进行显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用这些东西,首先要包含2个头文件:
#include <netdb.h>
#include <sys/socket.h>

 

一, GetHostByName

 struct hostent *gethostbyname(const char *name);
    这个函数的传入值是域名或者主机名,例如"www.google.com","wpc"等等。
    传出值,是一个hostent的结构(如下)。如果函数调用失败,将返回NULL。

    struct hostent {
      char  *h_name;
      char  **h_aliases;
      int   h_addrtype;
      int   h_length;
      char  **h_addr_list;
      }
      {
    解释一下这个结构:
    其中,
      char *h_name 表示的是主机的规范名。例如www.google.com的规范名其实是www.l.google.com
      char   **h_aliases 表示的是主机的别名。www.google.com就是google他自己的别名。有的时候,有的主机可能有好几个别名,这些,其实都是为了易于用户记忆而为自己的网站多取的名字。
      int   h_addrtype 表示的是主机ip地址的类型,到底是ipv4(AF_INET),还是ipv6(AF_INET6)
      int   h_length 表示的是主机ip地址的长度
      int   **h_addr_lisst 表示的是主机的ip地址,注意,这个是以网络字节序存储的。千万不要直接用printf带%s参数来打这个东西,会有问题的哇。所以到真正需要打印出这个IP的话,需要调用inet_ntop()。

    二,Inet_nTop

const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) :
    这个函数,是将类型为af的网络地址结构src,转换成主机序的字符串形式,存放在长度为cnt的字符串中。
    这个函数,其实就是返回指向dst的一个指针。如果函数调用错误,返回值是NULL。

下面是例程,有详细的注释。
#include <netdb.h>
#include <sys/socket.h>
int main(int argc, char **argv)
{
char *ptr,**pptr;
struct hostent *hptr;
char str[32];
/* 取得命令后第一个参数,即要解析的域名或主机名 */
ptr = argv[1];
/* 调用gethostbyname()。调用结果都存在hptr中 */
if( (hptr = gethostbyname(ptr) ) == NULL )
{
printf("gethostbyname error for host:%s/n", ptr);
return 0; /* 如果调用gethostbyname发生错误,返回1 */
}
/* 将主机的规范名打出来 */
printf("official hostname:%s/n",hptr->h_name);
/* 主机可能有多个别名,将所有别名分别打出来 */
for(pptr = hptr->h_aliases; *pptr != NULL; pptr++)
printf(" alias:%s/n",*pptr);
/* 根据地址类型,将地址打出来 */
switch(hptr->h_addrtype)
{
case AF_INET:
case AF_INET6:
pptr=hptr->h_addr_list;
/* 将刚才得到的所有地址都打出来。其中调用了inet_ntop()函数 */
for(;*pptr!=NULL;pptr++)
printf(" address:%s/n", inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)));
break;
default:
printf("unknown address type/n");
break;
}
return 0;

参考:http://blog.youkuaiyun.com/leesphone/archive/2008/03/02/2138775.aspx

http://blog.youkuaiyun.com/formiss/archive/2007/05/09/1601520.aspx

<think>我们遇到了inet_ntop隐式声明警告,这通常是因为我们没有包含定义该函数的头文件。inet_ntop函数定义在<arpa/inet.h>头文件中。在代码中,我们应该包含这个头文件。根据引用[2]中的代码,它使用了inet_ntop,但没有包含<arpa/inet.h>,这可能导致隐式声明警告。同样,在引用[1]的代码片段中,我们看到使用了INET_ADDRSTRLEN,这个常量也在<arpa/inet.h>中定义。解决方案:在代码中包含<arpa/inet.h>头文件。修改后的代码示例(基于引用[2]的代码):</think>### 解决 `inet_ntop` 隐式声明警告的完整方案 #### 问题原因分析 当在 `getaddrinfo` 结果处理中使用 `inet_ntop` 时出现隐式声明警告,根本原因是缺少必要的头文件声明。`inet_ntop` 函数声明在 `<arpa/inet.h>` 头文件中,未包含该头文件会导致编译器无法识别函数原型[^1][^2]。 #### 完整解决方案 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> // 关键修复:包含 inet_ntop 声明 int main() { const char *hostname = "www.example.com"; struct addrinfo hints, *res, *p; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; int status = getaddrinfo(hostname, NULL, &hints, &res); if (status != 0) { fprintf(stderr, "解析错误: %s\n", gai_strerror(status)); return 1; } for (p = res; p != NULL; p = p->ai_next) { char ipstr[INET6_ADDRSTRLEN]; void *addr; if (p->ai_family == AF_INET) { // IPv4 struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; addr = &(ipv4->sin_addr); } else { // IPv6 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr; addr = &(ipv6->sin6_addr); } // 修复点:包含 <arpa/inet.h> 后正确调用 inet_ntop const char *result = inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr); if (result == NULL) { perror("inet_ntop 错误"); continue; } printf("解析结果: %s -> %s\n", hostname, ipstr); } freeaddrinfo(res); return 0; } ``` #### 关键修复点说明 1. **添加必要头文件**: ```c #include <arpa/inet.h> // 包含 inet_ntop 函数原型 ``` 这是解决隐式声明警告的核心步骤,提供函数的正式声明[^1]。 2. **错误处理增强**: ```c const char *result = inet_ntop(...); if (result == NULL) { perror("inet_ntop 错误"); } ``` `inet_ntop` 失败时返回 `NULL`,需检查错误并打印 `errno`[^2]。 3. **地址转换规范**: - IPv4 使用 `sockaddr_in` 结构体 - IPv6 使用 `sockaddr_in6` 结构体 - 缓冲区大小使用 `INET6_ADDRSTRLEN` 常量(定义在 `<netinet/in.h>` 中) #### 常见错误场景及修复 | 错误场景 | 编译器警告/错误 | 解决方案 | |---------|----------------|---------| | 缺少 `<arpa/inet.h>` | `warning: implicit declaration of function 'inet_ntop'` | 添加头文件包含 | | 缓冲区大小不足 | `warning: 'inet_ntop' output truncated` | 使用 `INET6_ADDRSTRLEN`(46字节) | | 错误的结构体转换 | `segmentation fault` | 检查 `ai_family` 并正确转换地址类型 | #### 协议无关编程的最佳实践 1. **双栈支持**: ```c hints.ai_family = AF_UNSPEC; // 同时获取 IPv4/IPv6 地址 ``` 2. **安全转换**: ```c if (p->ai_family == AF_INET) { // IPv4 处理 } else if (p->ai_family == AF_INET6) { // IPv6 处理 } else { // 未知协议处理 } ``` 3. **内存管理**: ```c freeaddrinfo(res); // 必须释放 getaddrinfo 分配的内存 ``` #### 扩展应用:TCP 连接封装 ```c #include <arpa/inet.h> // 确保包含此头文件 int tcp_connect(const char *host, const char *port) { // ... [getaddrinfo 调用部分] ... for (p = res; p != NULL; p = p->ai_next) { // 地址转换调试 char ipstr[INET6_ADDRSTRLEN]; inet_ntop(p->ai_family, (p->ai_family == AF_INET) ? (void*)&((struct sockaddr_in*)p->ai_addr)->sin_addr : (void*)&((struct sockaddr_in6*)p->ai_addr)->sin6_addr, ipstr, sizeof ipstr); printf("尝试连接: %s\n", ipstr); // ... [连接逻辑] ... } // ... } ``` ### 相关问题 1. 如何正确处理 `getaddrinfo` 返回的多个 IP 地址? 2. 在 IPv6-only 环境中使用 `getaddrinfo` 需要注意什么? 3. `inet_ntop` 和 `inet_pton` 有什么区别及应用场景? 4. 如何通过 `getaddrinfo` 实现服务端绑定?[^3] 5. 为什么现代网络编程推荐使用 `getaddrinfo` 替代 `gethostbyname`?[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值