调用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;
}
相关推荐
liulilittle21 小时前
DNS泄露检测技术剖析:原理、实现
网络·ip·dns·泄露·通信·test·leak
小牛马爱写博客7 天前
DNS 服务器与 DHCP 服务器详解及配置指南
linux·运维·服务器·dns·dhcp
李小白杂货铺18 天前
家庭宽带可用DNS收集整理和速度评测2025版
dns·doh·家庭宽带·可用dns·速度评测·2025版·家庭宽带dns
星马梦缘1 个月前
计算机网络6 第六章 应用层——解决“怎么发请求、怎么回响应”的问题(邮件整体传输流程)
网络·计算机网络·域名·ftp·dns·dhcp
虚伪的空想家1 个月前
K8S的Pod为什么可以解析访问集群之外的域名地址
云原生·容器·kubernetes·dns·域名解析·pod·coredns
iphone1081 个月前
公司机密视频泄露频发?如何让机密视频只在公司内部播放
音视频·域名·视频加密·加密技术·视频安全·ovp防盗链·公司机密
卸任1 个月前
阿里云域名迁移到Cloudflare DNS管理
前端·dns
Dynadot_tech2 个月前
区块链 + 域名Web3时代域名投资的新风口(上)
web3·区块链·域名·dynadot·域名市场·域名投资
千码君20162 个月前
计算机网络:什么是任播
计算机网络·负载均衡·ddos·cdn·dns·任播·智能路由
高hongyuan2 个月前
网络故障排查及解决方案
网络·dns