调用gethostbyname实现域名解析(附源码)

VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章正在更新中...)https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_11931267.html 在使用socket套接字去连接远端的服务器时,需要使用IP和远端服务器建链,不能直接使用域名,但我们配置服务器地址时有时需要设置域名,这需要我们在代码中添加域名解析的模块,在连接服务器之前将域名解析成IP地址。

1、域名解析的完整流程

经常有朋友询问使用DNS系统查询IP的完整流程,这里我们普及一下这一过程。DNS服务器大致分为三种类型:根DNS服务器、顶级域DNS服务器和权威DNS服务器,其中顶级域DNS服务器主要负责诸如com、org、net、edu、gov 等顶级域名。

根DNS服务器存储了所有顶级域DNS服务器的 IP 地址,可以通过根服务器找到顶级域服务器,比如百度的域名www.baidu.com,根服务器会返回所有维护 com 这个顶级域服务器的 IP 地址。然后你任选其中一个顶级域服务器发送请求,该顶级域服务器拿到域名后能够给出负责当前域的权威服务器地址。以 百度的域名为例,顶级域服务器将返回所有负责百度这个域的权威服务器地址。接着任选其中一个权威服务器地址查询"www.baidu.com"的具体 IP 地址,最终权威服务器会返回给你具体的 IP 地址。此外,本地 DNS 服务器是具有缓存功能的,通常两天内的记录都会被缓存。

所以,通过DNS系统查询域名对应的 IP 的具体步骤可以总结为:

  • ① 操作系统先查本地 hosts文件 中是否有记录,如果有,则直接返回相对应映射的IP地址。
  • ② 如果本地hosts文件中没有配置,则主机向自己的本地DNS服务器发送查询报文,如果本地DNS服务器缓存中有,将直接返回结果。
  • ③ 如果本地服务器缓存中没有,则从内置在内部的根DNS服务器列表(全球13台,固定的IP地址)中选一个发送查询报文。
  • ④ 根服务器解析域名中的后缀名,告诉本地服务器负责该后缀名的所有顶级服务器列表。
  • ⑤ 本地服务器选择其中一个顶级域服务器发送查询请求,顶级域服务器拿到域名后继续解析,返回对应域的所有权威服务器列表。
  • ⑥ 本地服务器再向返回的权威服务器发送查询报文,最终会从某一个权威服务器上得到具体的 IP 地址。
  • ⑦ 主机返回结果IP。

2、调用gethostbyname发起域名解析

那如何实现将域名解析成IP地址呢?其实很简单,只要调用系统API函数gethostbyname即可实现。注意,gethostbyname函数可能会产生短暂的堵塞,该函数内部会先到网卡配置的DNS服务器上去查询域名对应的IP地址,如果本地DNS查询不到,则会到远端的DNS服务器上去查询,所以可能会比较耗时。

**所以我们需要将对gethostbyname函数调用的代码,放置在一个新的线程中,等解析出来后再将IP信息投递出来给主线程。**相关的代码如下所示:

cpp 复制代码
// 域名解析线程函数
UINT __stdcall QueryDomainThread( LPVOID pParam )
{
	char* lpszDomainName = (char*)pParam; 

	struct hostent *pHost = gethostbyname( lpszDomainName ); 
	if( NULL == pHost )  
	{   
		// ::PostMessage // 通知主线程域名解析失败
		return 0;   
	}

	if ( pHost->h_addr_list[0] != NULL ) 
	{ 
		u32 dwIP = (*(in_addr*)pHost->h_addr_list[0]).S_un.S_addr; 
		// ::PostMessage // 通知主线程域名解析成功,将解析出来的IP投递过去
	}  

	return 0; 
}

// 发起域名解析,创建新的线程去解析
LRESULT StartQueryDomain( char* lpszDomainName )
{
	// 此处不能直接将局部变量lpszDomainName传到线程函数中,因为启动线程的_beginthreadex返回时,线程函数不一定跑起来了
	// 所以最好搞一个成员变量或者全局变量,将lpszDomainName中的字符串拷贝下来,然后给_beginthreadex传递这个声明周期
	// 更长的变量
	strcpy( g_szMDomainName, lpszDomainName );

    // 线程函数QueryDomainThread的实现,上面已经给出
	HANDLE hThread= (HANDLE)_beginthreadex( NULL, 0, QueryDomainThread, (void*)g_szMDomainName, 0, NULL );
	if( hThread != NULL )
	{
		CloseHandle( hThread );
		return S_OK;
	}

	return S_FALSE;
}
相关推荐
ZachOn1y1 小时前
计算机网络:应用层 —— 应用层概述
计算机网络·http·https·应用层·dns
代码讲故事2 天前
子域提取工具,子域名收集神器,支持多种数据源和枚举选项,域名发现工具,可以为任何目标枚举海量的有效子域名,安全侦察工具,利用证书透明原则监控部署的新子域
网络·安全·证书·域名·提取·扫描·子域名
唯之为之3 天前
给网站设置三级域名
github·域名
Chicheng_MA7 天前
Linux DNS 协议概述
linux·dns
皓月盈江14 天前
阿里云ECS服务器域名解析
linux·服务器·阿里云·域名解析·ecs·cname记录类型·a记录类型
不知火猪17 天前
华为云域名网站,域名切换到Cloudflare CDN出现访问报错:DNS 重定向次过多
华为云·cdn·dns·cloudflare
SuperherRo1 个月前
基础入门-Web应用&架构搭建&域名源码&站库分离&MVC模型&解析受限&对应路径
架构·源码·域名·web·解析·路径
ink191 个月前
DoH(DNS on HTTPS)和DoT(DNS on TLS)协议详解
dns
雪碧聊技术1 个月前
Java网络编程1 - 介绍网络编程、网络编程三要素
网络·域名·协议·ip·网络通信·ipv4·ipv6
石牌桥网管1 个月前
DNS Resolver解析服务器出口IP查询
运维·网络·tcp/ip·dns