当前位置:首页 » 《随便一记》 » 正文

Linux C 域名解析(DNS)_无聊到发博客的菜鸟的博客

2 人参与  2021年11月21日 17:03  分类 : 《随便一记》  评论

点击全文阅读


简介

域名解析也叫域名指向、服务器设置、域名配置以及反向IP登记等等。说得简单点就是将好记的域名解析成IP,服务由DNS服务器完成,是把域名解析到一个IP地址,然后在此IP地址的主机上将一个子目录与域名绑定。

互联网中的地址是数字的IP地址,域名解析的作用主要就是为了便于记忆。

常用的域名解析函数有getaddrinfo()gethostbyname(),一些资料书认为gethostbyname()已经过时且不支持IPv6,更推荐使用getaddrinfo()

gethostbyname()的衍生版本gethostbyname2() 支持IPV6。



gethostbyname()

函数原型

#include <netdb.h>

struct hostent *gethostbyname(const char *name);

struct hostent{
    char *h_name;  			//official name
    char **h_aliases;  		//alias list
    int  h_addrtype;  		//host address type
    int  h_length;  		//address lenght
    char **h_addr_list;  	//address list
}
// 从该结构体可以看出,不只返回 IP 地址,还会附带其他信息,各位读者只需关注最后一个成员 h_addr_list。下面是对各成员的说明:
// h_name:官方主机名,返回字符串,结尾带NULL。
// h_aliases:别名,可以通过多个域名访问同一主机。
// h_addrtype:IPv4或者IPv6。
// h_length:保存IP地址长度,IPv4 的长度为 4 个字节,IPv6 的长度为 16 个字节。
// h_addr_list:这是最重要的成员,通过该成员以整数形式保存域名对应的 IP 地址,有负载均衡的服务器可解析出多个IP。

在这里插入图片描述

demo

#include <netdb.h>
#include <arpa/inet.h>
#include <stdio.h>

int main()
{
    struct hostent *host;
    int i = 0;

    host = gethostbyname("www.baidu.com");

    if (host != NULL)
    {
        // 官方域名
        printf("h_name = %s\r\n", host->h_name);

        // 别名
        for(i = 0; host->h_aliases[i]; i++)
        {
            printf("Aliases %d: %s\n", i+1, host->h_aliases[i]);
        }

        // 地址类型
        printf("Address type: %s\n", (host->h_addrtype==AF_INET) ? "AF_INET": "AF_INET6");

        // IP地址
        for(i = 0; host->h_addr_list[i]; i++)
        {
            printf("IP addr %d: %s\n", i+1, inet_ntoa(*(struct in_addr *)host->h_addr_list[i]));
        }
    }
    
    return 0;
}

// 输出
// h_name = www.a.shifen.com
// Aliases 1: www.baidu.com
// Address type: AF_INET
// IP addr 1: 14.215.177.38
// IP addr 2: 14.215.177.39



gethostbyname2()

函数原型

#include <netdb.h>

struct hostent *gethostbyname2(const char *name, int family);
// family可选 AF_INET(IPv4) 或 AF_INET6(IPv6)

struct hostent{
    char *h_name;  			//official name
    char **h_aliases;  		//alias list
    int  h_addrtype;  		//host address type
    int  h_length;  		//address lenght
    char **h_addr_list;  	//address list
}
// 从该结构体可以看出,不只返回 IP 地址,还会附带其他信息,各位读者只需关注最后一个成员 h_addr_list。下面是对各成员的说明:
// h_name:官方主机名,返回字符串,结尾带NULL。
// h_aliases:别名,可以通过多个域名访问同一主机。
// h_addrtype:IPv4或者IPv6。
// h_length:保存IP地址长度,IPv4 的长度为 4 个字节,IPv6 的长度为 16 个字节。
// h_addr_list:这是最重要的成员,通过该成员以整数形式保存域名对应的 IP 地址,有负载均衡的服务器可解析出多个IP。

demo

如果把demo中的AF_INET6改成AF_INET,则效果和gethostbyname()一致。

#include <netdb.h>
#include <arpa/inet.h>
#include <stdio.h>

int main()
{
    struct hostent *host;
    int i = 0;
    char buf[100];
 
    host = gethostbyname2("iservice.10010.com", AF_INET6);

    if (host != NULL)
    {
        // 官方域名
        printf("h_name = %s\r\n", host->h_name);

        // 别名
        for(i = 0; host->h_aliases[i]; i++)
        {
            printf("Aliases %d: %s\n", i+1, host->h_aliases[i]);
        }

        // 地址类型
        printf("Address type: %s\n", (host->h_addrtype==AF_INET) ? "AF_INET": "AF_INET6");

        // IP地址
        for(i = 0; host->h_addr_list[i]; i++)
        {
            printf("IP addr %d: %s\n", i+1, inet_ntop(AF_INET6, host->h_addr_list[i], buf, 100));
        }
    }
    
    return 0;
}

// 输出
// h_name = iservice.10010.com.w.cdngslb.com
// Aliases 1: iservice.10010.com
// Address type: AF_INET6
// IP addr 1: 240e:95c:2002:1:3::3fe
// IP addr 2: 240e:95c:2002:1:3::3fd



getaddrinfo()

函数原型

#include <sys/socket>
#include <netdb.h>

int getaddrinfo(const char *host, const char *service, const struct addrinfo *hints, struct addrinfo **result);

// @param host:域名,如www.baidu.com。
// @param service:服务名,如http、ftp。
// @param hints:该结构规定了选择通过result返回的socket地址结构的标准。一般可以设置为
// {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL}
// @param result:返回一个结构列表而不是单个结构。
// @return:成功返回0,成功返回后要使用freeaddrinfo(struct addrinfo *result)来释放动态申请的内存。

struct addrinfo{
    int             ai_flags;
    int             ai_family;
    int             ai_socktype;
    int             ai_protocol;
    size_t          ai_addrlen;
    char            *ai_canonname;
    struct sockaddr *ai_addr;
    struct addrinfo *ai_next;
}

在这里插入图片描述

hints参数

hints参数为如何选择getaddrinfo()返回的socket地址结构指定了更多的标准。当用作hints 参数时只能设置addrinfo结构的ai_flags、ai_family、ai_socktype以及ai_protocol字段,其他字段未用到,并将应该根据具体情况将其初始化为0或NULL。

hints .ai_family字段选择了返回的socket的地址结构的域,可以为AF_INET(IPv4)、AF_INET6(IPv6)(或其他的一些AF_*常量,只要实现支持)。如果需要获取所有种类socket地址结构,那么可以将这个字段的值指定为AF_UNSPEC。

hints .ai_socktype字段指定了socket类型,可以是SOCK_STREAM或SOCK_DGRAM,也可以为0,那么任意类型的socket都是可以接受的。

hints .ai_protocol字段表示选择的socket协议,可以是IPPROTO_TCP或IPPROTO_UDP,也可以为0,表示调用者接受任何协议。

hints .ai_flags字段是一个位掩码,它会改变getaddrinfo()的行为,一般为0,详情请参考《Linux/UNIX系统编程手册》P997。

demo

#include <netdb.h>
#include <arpa/inet.h>
#include <stdio.h>

int main()
{
    int rc;
    char buf[100];
    struct addrinfo *result = NULL;
	struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL};

	if ((rc = getaddrinfo("iservice.10010.com", NULL, &hints, &result)) == 0)
	{
		struct addrinfo* res = result;

		while (res)
		{
			if (res->ai_family == AF_INET)
			{
                printf("%s\r\n", inet_ntoa(((struct sockaddr_in *)res->ai_addr)->sin_addr));
			}
            else if (res->ai_family == AF_INET6)
            {
                printf("%s\r\n", inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)res->ai_addr)->sin6_addr), buf, 100));
            }
            
			res = res->ai_next;
		}

		freeaddrinfo(result);
	}
}

// 输出
// 58.49.225.143
// 58.49.225.144
// 58.49.225.145
// 58.49.225.142
// 58.49.225.148
// 58.49.225.147
// 58.49.225.141
// 58.49.225.146
// 240e:95c:2002:1:3::3fe
// 240e:95c:2002:1:3::3fd

点击全文阅读


本文链接:http://zhangshiyu.com/post/31153.html

地址  返回  结构  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1