调用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;
}
相关推荐
东锋1.311 小时前
IP、网关、子网掩码、DNS 之间的关系详解
网关·智能路由器·ip·dns·子网掩码
昵称为空C3 天前
局域网内dns服务器dnsmasq服务搭建
docker·dns
六个点4 天前
DNS与获取页面白屏时间
前端·面试·dns
卷心菜不卷Iris10 天前
第1章大型互联网公司的基础架构——1.3 HTTP-DNS
网络·网络协议·http·dns·互联网大厂·http-dns·基础架构
聚名网18 天前
如何修改DNS解析?
dns·修改dns解析
帝恩思科技1 个月前
如何轻松实现域名指向服务器
域名·域名注册·域名建站·老域名
火山引擎边缘云1 个月前
揭秘字节跳动内部流量调度与容灾实践【上】
后端·云计算·dns
thinking-fish1 个月前
DNS介绍(5):DNS 劫持及解决方案
网络·网络安全·dns·dns劫持
hong_zc1 个月前
网络原理(四)—— 网络层、数据链路层 与 DNS
网络·dns·数据链路层·网络层
Algorithm-0072 个月前
软件测试预备知识⑤—搭建 DNS 服务器
运维·服务器·dns