【TCP/IP】IP地址与域名之间的转换 - gethostbyname 和 gethostbyaddr函数

news2024/12/25 3:25:57

目录

域名系统

DNS服务器

IP地址和域名之间的转换

通过域名获取IP地址

通过IP地址获取域名


域名系统

        域名系统(英文:Domain Name System,缩写:DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。

DNS服务器

        所有计算机中会保存记录默认DNS服务器的地址,通过默认DNS服务器便可得到相应域名的IP地址信息。在浏览器地址栏中输入域名后,浏览器会通过默认DNS服务器来获取该域名对应的IP地址信息,从而建立起与目标服务器之间的连接。

补充:

        在Linux系统中,有两条指令可以帮助我们查看DNS服务器地址及其对应的IP地址。

  • ping:能够查看某一域名对应的IP地址
  • nslookup:用于查询DNS的记录,查询域名解析是否正常,在网络故障时用来诊断网络问题

        计算机内置的默认DNS服务器并不知道网络上所有域名的IP地址。当默认DNS服务器无法解析时,则会询问其他DNS服务器,进行多次迭代直到查找到为止,最终把查询记录交还给用户。

        如上图,描述了在默认DNS服务器无法查找到目标域名IP地址时的更迭过程。不难看出,DNS是一种层次化管理的分布式数据库系统。

IP地址和域名之间的转换

        在之前,我们编写的程序都是以IP+端口号的形式来构建连接,然而这只限于IP地址较为固定的场景。当我们需要访问互联网中各类网页时,依靠输入IP地址和端口号这种方式将会显得十分笨拙。(试想如果IP地址发生变化,程序是否就得重新编写)那么,什么方法可以解决这个问题呢?

        域名相对于IP地址,变化更少且稳定,那么利用域名来编写程序便可使维护变得更加轻松。在网络编程中,也有一个合适的函数,能够帮助我们通过域名地址来解析出所需要的各类信息。

通过域名获取IP地址

        使用以下函数可以通过传递域名的字符串形式来获取IP地址。

#include <netdb.h>
struct hostent * gethostbyname(const char * hostname);

//成功时返回hostent结构体地址,失败时返回NULL指针

        通过gethostbyname函数,我们只需要传递域名的字符串,就可以得到域名对应的IP地址。但需要注意的是,返回的数据类型是一个结构体形式。该结构体定义如下:

/* Description of data base entry for a single host.  */
struct hostent
{
  char *h_name;			/* Official name of host.  */
  char **h_aliases;		/* Alias list.  */
  int h_addrtype;		/* Host address type.  */
  int h_length;			/* Length of address.  */
  char **h_addr_list;		/* List of addresses from name server.  */
#ifdef __USE_MISC
# define	h_addr	h_addr_list[0] /* Address, for backward compatibility.*/
#endif
};

        除了IP地址外,该结构体还带有其他信息。以下是对该结构体中各变量意义的描述:

h_name
用以保存官方域名

h_alìases
用以保存多个可能存在的域名

h_addrtype
用以保存在h_addr_list中IP地址对应的地址族信息。若是IPv4,则变量为AF_INET。
h_length
用以保存IP地址的长度 。若是IPv4地址(4个字节存储) ,则该值为4;IPv6时(16个字节存储),则值为16。

h_addr_list
用以保存多个可能存在的IP地址,变量以char *形式保存域名对应的IP地址 。

        结构体的抽象结构如下:

        让我们尝试一下利用gethostbyname(在netdb.h头文件中)函数来编写一个域名转IP的小程序。

demo_byname.cpp

#include <netdb.h>
#include <iostream>
#include <arpa/inet.h>
int main()
{
    struct hostent *host;
    std::string domainAddress;
    std::cout << "Please input a website addreess" << std::endl;
    std::cin >> domainAddress;

    host = gethostbyname(domainAddress.c_str());
    if (!host)
    {
        std::cout << "Get host error" << std::endl;
        return -1;
    }
    //输出官方域名
    std::cout << "Official name:" << host->h_name << std::endl;
    //输出其他可能存在的多个域名
    for (size_t i = 0; host->h_aliases[i]; i++)
    {
        std::cout << "Aliases " << i + 1 << ":" << host->h_aliases[i] << std::endl;
    }
    //输出地址族信息
    std::cout << "Address type: " << ((host->h_addrtype == AF_INET) ? "AF_INET" : "AF_INET6") << std::endl;
    //输出可能存在的多个(域名)对应的IP地址
    for (size_t i = 0; host->h_addr_list[i]; i++)
    {
        std::cout << "IP Address " << i + 1 << ":" << inet_ntoa(*(struct in_addr*)host->h_addr_list[i]) << std::endl;
    }

    return 0;
}

输出信息:

        需要注意的是,在h_addr_list这个变量中,虽然数据类型是字符串指针数组,但是元素的实际指向是in_addr结构体变量地址值而非字符串,如图所示。

        因此,在输出时,请根据需要将数据类型作相应的转换。

inet_ntoa(*(struct in_addr*)host->h_addr_list[i]);

        疑问:为什么hostent结构体中的成员h_addr_list指向的数组类型是char *,但其形式却是in_addr结构体?

        答:在C支持void *指针之前,在结构定义上,人们把char * 视作“通用指针”。而设计者在设计之初,并未只考虑IPv4,也考虑到了IPv6的格式。在创建结构体时,如果h_addrtype不是AF_INET(IPv4格式),那么h_addr_list中将包含非struct in_addr的结构体类型,设计者为了使结构体具有通用性,用char * 来对这两种不同的结构形式做通用化,这样便免去了重新去设计新的结构体的繁琐过程。(事实也表明,设计者当时做对了,现在struct in_addr将在不久逐渐被IPv6地址所取代)

通过IP地址获取域名

        除了通过域名获取对应的IP地址外,我们也可以通过IP地址来获取域名。gethostbyaddr这个函数可以帮助我们通过传入含有IP地址信息的char *指针(为什么用char *以及涉及到的转换相信也不难理解了),来获取对应的hostent结构体。

#include <netdb.h>

struct hostent * gethostbyaddr(const char * addr , socklen_t len , int family);

//成功时返回hostent结构体变量地址值,失败时返回NULL指针。

/* 变量含义 */
//addr:含有IP地址信息的in_addr结构体指针。为了同时传递IPv4地址之外的其他信息,该变量的类型声明为char指针
//len:向第一个参数传递的地址信息的字节数,IPv4时为4,IPv6时为16
//family:传递地址族信息,IPv4时为AF_INET,IPv6时为AF_INET6

        编写一个demo来验证这个功能吧~

demo_byadd.cpp

#include <netdb.h>
#include <iostream>
#include <arpa/inet.h>
int main()
{
    struct hostent *host;
    std::string ipAddress;
    struct sockaddr_in addr;

    std::cout << "Please input a website IP addreess:" << std::endl;
    std::cin >> ipAddress;

    addr.sin_addr.s_addr=inet_addr(ipAddress.c_str());
    //注意是在 .sin_addr 处转换为char *,以及注意上面是在 .s_addr 上赋值
    host = gethostbyaddr((char*)&addr.sin_addr,4,AF_INET);

    if (!host)
    {
        std::cout << "Get host error" << std::endl;
        return -1;
    }
 
    std::cout << "Official name:" << host->h_name << std::endl;

    for (size_t i = 0; host->h_aliases[i]; i++)
    {
        std::cout << "Aliases " << i + 1 << ":" << host->h_aliases[i] << std::endl;
    }
 
    std::cout << "Address type: " << ((host->h_addrtype == AF_INET) ? "AF_INET" : "AF_INET6") << std::endl;

    for (size_t i = 0; host->h_addr_list[i]; i++)
    {
        std::cout << "IP Address " << i + 1 << ":" << inet_ntoa(*(struct in_addr*)host->h_addr_list[i]) << std::endl;
    }

    return 0;
}

输出信息(通过ping 获取到的Google IP地址):

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/617723.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python如何竖直输出?

Python如何竖直输出&#xff1f; Python作为一种功能强大的编程语言&#xff0c;在数据分析、人工智能、Web开发等领域得到广泛应用。不过&#xff0c;对于一些初学者或者日常编程较少的开发者来说&#xff0c;可能会遇到一些问题&#xff0c;例如如何竖直输出。 在Python中&…

软件过程与管理——民宿管理系统的项目实践报告(文档+ppt+图表源文件)

目录 一、题目分析与设计 二、评分标准 三、文档目录 四、文档下载 一、题目分析与设计 1、团队组织建设 同学们以3-5人为一组&#xff0c;最多5人一组&#xff0c;每组选择一个具体的软件项目&#xff0c;如现进行的个人毕业设计题目等为主题&#xff0c;要求项目的工作…

量子模拟器中的“弯曲时空”

光子盒研究院出品 当你想解释宇宙尺度的现象时&#xff0c;相对论很有效&#xff1a;比如黑洞碰撞时产生的引力波&#xff1b;量子理论在描述粒子尺度的现象时效果很好&#xff08;比如原子中单个电子的行为&#xff09;。但是&#xff0c;将这两者以一种完全令人满意的方式结合…

【SpinalHDL快速入门】4.6、复合类型之Vec

文章目录 1.1、描述1.2、声明1.2.1、实例 1.3、运算符1.3.1、比较&#xff08;Comparison&#xff09;1.3.2、类型转换&#xff08;Type cast&#xff09;1.3.3、杂项&#xff08;Misc&#xff09;1.3.4、Lib辅助函数&#xff08;Lib helper functions&#xff09; 1.1、描述 …

直播签到功能(互动功能发起端JS-SDK)

功能概述 本功能只支持角色为讲师/嘉宾/助教/管理员的用户进行发起和停止等操作。发起签到时可自定义设置签到时长和签到提示语。 图 / 讲师在直播客户端软件f中操作界面 图 / 学员直播观看页弹出签到界面 代码示例 注意&#xff0c;在开始以下步骤前需要先进行全局初始化设置…

chatgpt赋能python:Python-如何快速高效地求两数之和

Python - 如何快速高效地求两数之和 介绍 Python 是一种高级编程语言&#xff0c;适用于各种领域的软件开发。本文将介绍使用 Python 完成两个数字之和的操作。Python 以其清晰、简洁、易于学习和使用的特性闻名于世&#xff0c;既能作为脚本语言&#xff0c;又能进行面向对象…

基于stm32的超声波测距

文章目录 一、HC-SR04超声波测距模块说明1、产品特点2、电气参数3、HC-SR04超声波测距模块4、超声波时序图 二、 CUBEMX配置三、keil配置代码 模块选择&#xff1a; stm32f103c8芯片 HC-SR04超声波测距模块 一、HC-SR04超声波测距模块说明 1、产品特点 HC-SR04 超声波测距模块…

chatgpt赋能python:Python如何将两张图片叠加

Python如何将两张图片叠加 介绍 图像处理是计算机视觉领域的重要应用&#xff0c;而Python已经成为了图像处理中最流行的编程语言之一。在图像处理的过程中&#xff0c;有时需要将两张图片叠加在一起&#xff0c;这就需要用到Python中的图像叠加技术。 本文将介绍Python中如…

chatgpt赋能python:Python如何空一行:介绍

Python如何空一行&#xff1a;介绍 在Python编程中&#xff0c;经常需要在输出文字或代码时进行空行分隔。一个常用的场景就是在代码中加入注释&#xff0c;将注释与代码分开&#xff0c;使代码逻辑更加清晰易懂。在某些情况下&#xff0c;也需要在输出文字时进行空行分割&…

一次方维o2o商城PHP审计学习

PHP审计源码学习 一、渗透测试 起因是朋友问fanwei o2o源码搭建的站后台能不能拿shell&#xff0c;于是我进后台进行了一番尝试&#xff0c;各功能点没什么进展&#xff0c;好多地方过滤了&#xff0c;上传也是白名单&#xff0c;编辑器的1day修了&#xff0c;万幸的是有个拿…

priority_queue(优先级队列)模拟实现(堆方式)

目录 priority_queue初步介绍 堆 堆的模拟实现 接口实现 插入(push) AdJustUp(向上排序)接口 删除(pop) AdJustDown(向下排序算法) 适配器堆总结 仿函数 用仿函数对堆进一步封装 用堆进行封装优先级队列 代码总结 priority_queue初步介绍 priority_queue的性质是…

BOOST 恒压控制驱动芯片,外围电路简单

应用说明 Hi8000 是一款外围电路简单的 BOOST 升压恒压控制驱动芯片&#xff0c;适用于 2.7-40V 输入电压范围的升压恒压电源应用领域&#xff0c;启动电压可以低至 2.5V&#xff0c;可以广泛应用 于太阳能、便携式数码产品&#xff0c;锂电升压应用等供电领域。 应用领域 移…

Day_44希尔排序

目录 一. 关于希尔排序 二. 希尔排序的实现过程 三. 希尔排序的代码实现 1. 核心代码 2. 修改后的代码 四. 代码展示 五. 数据测试 六. 总结与反思 一. 关于希尔排序 希尔排序按其设计者希尔&#xff08;Donald Shell&#xff09;的名字命名&#xff0c;该算法由希尔在 19…

报名抽奖功能(互动功能接收端JS-SDK)

功能概述 本模块主要处理报名抽奖相关逻辑&#xff0c;如抽奖开始、结束和更新等事件消息。 图&#xff1a;抽奖--效果截图 图&#xff1a;抽奖--效果截图 初始化及销毁 在实例化该模块并进行使用之前&#xff0c;需要对SDK进行初始化配置&#xff0c;详细见参考文档。 在线…

直播教学答题卡(互动功能发起端JS-SDK)

本 SDK 主要包括发起答题卡、管理答题卡题库等功能。以下操作仅支持角色为讲师/嘉宾/助教/管理员的用户执行。 答题卡可以分为快速问答和普通答题卡。 快速问答只有单选和多选两种类型&#xff0c;没有具体的选项内容&#xff0c;最多可有 5 个选项。普通答题卡题目类型包括&a…

MySQL:索引

索引&#xff0c;在MySQL中非常重要。它能提高数据库的性能&#xff0c;不用加内存&#xff0c;不用改程序&#xff0c;不用调sql&#xff0c;只要执行 正确的 create index &#xff0c;查询速度就可能提高成百上千倍。 但是&#xff0c;查询速度的提高是以插入、更新、删除的…

Lora模型训练-koya SS GUi

前提 现在大部分 AI 产品采用的的大模型(dreamboth),但是在产品的训练中也发现了不仅仅需要较大的内存还需要好的 GPU 成本较高,而且模型较大修改只能重新训练不能修改,为了解决这个问题开始推荐 lora 小模型时代.接下来讲解 lora 模型以及使用小模型(lora)的Koya.SS.GUI的流程…

LeetCode-031. 最近最少使用缓存

HashMap扩容&#xff1a;(30条消息) 代码优化 | 如何设置HashMap的初始值大小_hashmap指定初始值大小_死牛胖子的博客-CSDN博客 1、哈希表LinkedList 超出时间&#xff08;&#xff09; Collection(集合):容器,用于存放对象(引用类型。基本类型需要自动装箱) List(列表):元素…

正则表达式(一):基础命令及字符

正则表达式一-基础命令及字符 一、常用命令补充&#xff1a;1.grep&#xff1a;2.sort&#xff1a;3.uniq&#xff1a;快速去重4.tr&#xff1a;5.cut&#xff1a;6.split&#xff1a;文件拆分7.paste&#xff1a;合并文件8.例题应用&#xff1a; 二、正则表达式&#xff1a;1.…

UID和cookie的查找

1、首先在浏览器中输入www.weibo.cn(如图1)&#xff0c; 然后按回车键&#xff0c;打开微博&#xff08;如图2&#xff09;。 图1 图2 2、在上图空白处单击鼠标右键&#xff0c;在显示出的对话框中点击【检查】&#xff0c;如下图。 3、如下图&#xff0c;点击【网络】或者【N…