【Linux C | 网络编程】getaddrinfo 函数详解及C语言例子

news2024/10/5 15:23:30

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍 getaddrinfo 函数 🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭
⏰发布时间⏰:2024-03-01 14:15:54

本文未经允许,不得转发!!!

目录

  • 🎄一、概述
  • 🎄二、getaddrinfo 函数
    • ✨2.1 getaddrinfo 函数介绍
    • ✨2.2 struct addrinfo 结构体说明
  • 🎄三、gai_strerror、freeaddrinfo 函数
    • ✨3.1 gai_strerror 函数介绍
    • ✨3.2 freeaddrinfo 函数介绍
  • 🎄四、getaddrinfo 函数使用例子
  • 🎄五、总结


在这里插入图片描述

🎄一、概述

前面介绍过域名和IP地址之间转换的两个函数:gethostbynamegethostbyaddr,但是这两个函数仅仅支持IPv4。本文再介绍一个可支持 IPv4 和 IPv6 的函数getaddrinfo,该函数可以处理名字到地址以及服务到端口这两种转换。


在这里插入图片描述

🎄二、getaddrinfo 函数

✨2.1 getaddrinfo 函数介绍

  • 1、函数原型:

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netdb.h>
    int getaddrinfo(const char *node, const char *service,
                    const struct addrinfo *hints, struct addrinfo **res);
    void freeaddrinfo(struct addrinfo *res);
    const char *gai_strerror(int errcode);
    
  • 2、函数描述:
    getaddrinfo函数根据给定的主机名和服务名,返回一个struct addrinfo结构链表,每个struct addrinfo结构都包含一个互联网地址。getaddrinfo函数将gethostbynamegetservbyname函数提供的功能组合到一个接口中,但与后一个函数不同,getaddrinfo是可重入的,可支持IPv4、IPv6。

  • 3、函数参数:

    • node:一个主机名或地址串( IPv4的点分十进制数串或IPv6的十六进制数串)。如果hints.ai_flags包含AI_NUMERICHOST标志,则此参数必须是IP地址字符串;

    • service:一个服务名或十进制端口号数串。如果此参数被设置为一个服务名称,则会将其转换为相应的端口号。如果设置为NULL,则返回的套接字地址的端口号将保持未初始化状态。如果在hints.ai_flags中指定了AI_NUMERICSERV,并且此参数不为NULL,则此参数必须指向包含数字端口号的字符串;

    • hints:hints参数可以是一个空指针,也可以是一个指向某个addrinfo结构的指针,调用者在这个结构中填入关于期望返回的信息类型的暗示。hints参数中,调用者可以设置的字段有:ai_flags、ai_family、ai_socktype、ai_protocol。其中,ai_flags取值如下表:

      取值说明
      AI_PASSIVE套接字将用于被动打开.
      AI_CANONNAME告知getaddrinfo函数返回主机的规范名字.
      AI_NUMERICHOST防止任何类型的名字到地址映射,hostname参数必须是一个地址串。
      AI_NUMERICSERV防止任何类型的名字到服务映射, service参数必须是一个十进制端口号。AI__V4MAPPED
      AI_V4MAPPED如果同时指定ai_family成员的值为AF_INET6,那么如果没有可用的AAAA记录,就返回与A记录对应的IPv4映射的IPv6地址。
      AI_ALL如果同时指定AI_V4MAPPED标志,那么除了返回与AAAA记录对应的IPv6地址外,还返回与A记录对应的IPv4映射的IPv6地址。
      AI_ADDRCONFIG按照所在主机的配置选择返回地址类型,也就是只查找与所在主机回馈接口以外的网络接口配置的IP地址版本一致的地址。

      ai_family 取值一般为AF_XXX,例如:AF_INETAF_INET6AF_UNSPEC(不限制IP地址协议);
      ai_socktype 取值一般为SOCK_XXX,例如:SOCK_STREAMSOCK_DGRAM
      ai_protocol 字段指定返回的套接字地址的协议。在该字段中指定0表示getaddrinfo函数可以返回具有任何协议的套接字地址。

    • res:传出参数,如果本函数返回成功0,则 res 参数指向的变量已被填入一个指针,它指向的是由其中的 ai_next 成员串接起来的 addrinfo 结构链表。

  • 4、返回值:
    成功返回0,失败返回非0,取值如下表:

    常值说明
    EAI_AGAIN名字解析中临时失败
    EAI_BADFLAGSai_flags的值无效
    EAI_FAIL名字解析中不可恢复地失败
    EAI_FAMILY不支持ai_family
    EAI_MEMORY内存分配失败
    EAI_NONAMEhostname或service未提供,或者不可知
    EAI_OVERFTOW用户参数缓冲区溢出(仅限getnameinfo( )函数)
    EAI_SERVICE不支持ai_socktype类型的service
    EAI_SOCKTYPE不支持ai_socktype
    EAI_SYSTEM在errno变量中有系统错误返回

✨2.2 struct addrinfo 结构体说明

struct addrinfo结构体定义在头文件 netdb.h 中,结构体声明如下:

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

在这里插入图片描述
结构体字段说明:

  • ai_flags:标志,在调用时使用,具体取值见上面 hints参数 的说明;
  • ai_family:IP协议族,一般取值有AF_INETAF_INET6AF_UNSPEC(不限制IP地址协议);
  • ai_socktype:socket类型,取值一般为SOCK_XXX,例如:SOCK_STREAMSOCK_DGRAM
  • ai_protocol:此字段指定返回的套接字地址的协议,一般有IPPROTO_UDPIPPROTO_TCP
  • ai_addrlen:返回的地址结构体ai_addr的长度。一般IPv4是4,IPv6是16;
  • ai_addr:存储IP地址数据,一般转换成struct sockaddr_instruct sockaddr_in6使用;
  • ai_canonname:正式的、标准的名称;
  • ai_next:用作链表结点指针,指向下一个struct addrinfo结点。

在这里插入图片描述

🎄三、gai_strerror、freeaddrinfo 函数

在使用 getaddrinfo 函数时,还有两个函数也会使用到,下面简单介绍一下这两个函数。

✨3.1 gai_strerror 函数介绍

  • 1、函数原型:
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netdb.h>
    const char *gai_strerror(int errcode);
    
  • 2、函数描述:
    getaddrinfo出错会返回的非0错误值,gai_strerror以这些值为它的唯一参数,返回一个指向对应的出错信息串的指针。
    常值说明
    EAI_AGAIN名字解析中临时失败
    EAI_BADFLAGSai_flags的值无效
    EAI_FAIL名字解析中不可恢复地失败
    EAI_FAMILY不支持ai_family
    EAI_MEMORY内存分配失败
    EAI_NONAMEhostname或service未提供,或者不可知
    EAI_OVERFTOW用户参数缓冲区溢出(仅限getnameinfo( )函数)
    EAI_SERVICE不支持ai_socktype类型的service
    EAI_SOCKTYPE不支持ai_socktype
    EAI_SYSTEM在errno变量中有系统错误返回

✨3.2 freeaddrinfo 函数介绍

  • 1、函数原型:

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netdb.h>
    void freeaddrinfo(struct addrinfo *res);
    
  • 2、函数描述:
    由getaddrinfo返回的所有存储空间都是动态获取的(譬如来自malloc调用),包括addrinfo结构、ai_addr结构和ai_canonname字符串。这些存储空间需要通过调用freeaddrinfo返还给系统。

  • 3、参数
    res:res参数应指向由getaddrinfo返回的第一个addrinfo结构。这个链表中的所有结构以及由它们指向的任何动态存储空间(譬如套接字地址结构和规范主机名)都被释放掉。

  • 4、注意:
    如果getaddrinfo成功返回后,我们为了保存返回的信息而仅仅复制了返回的addrinfo结构,在调用freeaddrinfo后,就会存在一个错误:我们前面复制的addrinfo结构中的指针指向的内存空间已在调用freeaddrinfo后返还给系统。
    这种只复制结构体而没复制结构体字段指向的内容的方式称为浅复制;复制结构体又复制结构体字段指向的内容的方式称为深复制。上面例子中,如果确实要保存信息,可以使用深复制来保存。


在这里插入图片描述

🎄四、getaddrinfo 函数使用例子

// getaddrinfo_sample.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
    struct addrinfo hints, *result, *rp;// 定义addrinfo结构体变量
    int err;                         	// getaddrinfo函数返回值
    char ipstr[INET6_ADDRSTRLEN];       // 存储IP地址字符串的缓冲区

    if (argc != 2) {                    // 检查命令行参数数量是否正确
        fprintf(stderr, "Usage: %s hostname\n", argv[0]);
        return -1;
    }

    memset(&hints, 0, sizeof(hints));  	// 初始化hints结构体
    hints.ai_family = AF_UNSPEC;		// 不限制IP地址版本
    hints.ai_socktype = SOCK_STREAM;	// 使用TCP协议

    if ((err = getaddrinfo(argv[1], NULL, &hints, &result)) != 0) {  // 解析主机名并将结果存储在result指针中
        fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(err));
        return -1;
    }

    printf("IP addresses for %s:\n", argv[1]);

    for (rp = result; rp != NULL; rp = rp->ai_next) {	// 遍历result指针中的所有套接字地址结构
        void *addr;
        char *ipver;

        if (rp->ai_family == AF_INET) {	// IPv4地址
            struct sockaddr_in *ipv4 = (struct sockaddr_in *)rp->ai_addr;
            addr = &(ipv4->sin_addr);
            ipver = "IPv4";
        } else { 						// IPv6地址
            struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)rp->ai_addr;
            addr = &(ipv6->sin6_addr);
            ipver = "IPv6";
        }

        inet_ntop(rp->ai_family, addr, ipstr, sizeof(ipstr));  // 将套接字地址结构转换为IP地址字符串
        printf("  %s: %s\n", ipver, ipstr);                    // 打印IP地址和版本号
    }

    freeaddrinfo(result);   // 释放由getaddrinfo函数分配的内存

    return 0;    // 程序正常退出
}

运行结果:
下面是分别查询www.baidu.com(百度)、www.goolge.com(谷歌)、blog.csdn.net(CSDN)、localhost(本地主机名)、ip6-localhostip6-localnet的打印结果。
在这里插入图片描述

localhost(本地主机名)、ip6-localhostip6-localnet,这三个在/etc/hosts文件中有说明,可以发现与查询的一致。
在这里插入图片描述


在这里插入图片描述

🎄五、总结

👉本文重点介绍了 getaddrinfo、freeaddrinfo、gai_strerror 三个函数,并给出C语言使用例子。

通过本文的介绍,我们深入探讨了 Linux 系统中 getaddrinfo 函数的定义和使用场景。getaddrinfo 函数在网络编程中扮演着重要角色,允许开发人员根据主机名和服务名动态获取地址信息,为构建灵活且健壮的网络应用提供了便利。希望本文能帮助您更好地了解并应用 getaddrinfo 函数。

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

参考资料:
1、Linux的man手册
2、《Unix网络编程卷1》

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

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

相关文章

视频和音频使用ffmpeg进行合并和分离(MP4)

1.下载ffmpeg 官网地址&#xff1a;https://ffmpeg.org/download.html 2.配置环境变量 此电脑右键点击 属性 - 高级系统配置 -高级 -环境变量 - 系统变量 path 新增 文件的bin路径 3.验证配置成功 ffmpeg -version 返回版本信息说明配置成功4.执行合并 ffmpeg -i 武家坡20…

群控代理IP搭建教程:打造一流的网络爬虫

目录 前言 一、什么是群控代理IP&#xff1f; 二、搭建群控代理IP的步骤 1. 获取代理IP资源 2. 配置代理IP池 3. 选择代理IP策略 4. 编写代理IP设置代码 5. 异常处理 三、总结 前言 群控代理IP是一种常用于网络爬虫的技术&#xff0c;通过使用多个代理IP实现并发请求…

【设计模式】(二、)设计模式六大设计原则

一、 设计原则概述 设计模式中主要有六大设计原则&#xff0c;简称为SOLID &#xff0c;是由于各个原则的首字母简称合并的来(两个L算一个,solid 稳定的)&#xff0c;六大设计原则分别如下&#xff1a; ​ 1、单一职责原则&#xff08;Single Responsibitity Principle&#…

Flutter SDK 常见问题

镜像配置 配置pub服务的镜像地址&#xff1a; export PUB_HOSTED_URLhttps://pub.flutter-io.cn export FLUTTER_STORAGE_BASE_URLhttps://storage.flutter-io.cn 第一次运行项目很慢&#xff0c;搜索整个Flutter SDK项目&#xff0c;使用以下内容替换google和mavenCentral仓…

【精选】Java项目介绍和界面搭建——拼图小游戏 中

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

福派斯课堂:猫软便呕吐不吃东西有什么影响?

&#x1f431; 猫软便、呕吐、不吃东西&#xff0c;这些症状听起来让人担心。作为猫咪的主人&#xff0c;看到它们不舒服&#xff0c;心里肯定不好受。那么&#xff0c;这些症状对猫咪有什么影响呢&#xff1f; 1️⃣ 营养失衡&#xff1a;如果猫咪不吃东西&#xff0c;身体就无…

[⑥5G NR]: 无线接口协议,信道映射学习

5G系统整体包括核心网、接入网以及终端部分&#xff0c;接入网与终端间通过无线空口协议栈进行连接。无线接口可分为三个协议层&#xff1a;物理层&#xff08;L1&#xff09;、数据链路层&#xff08;L2&#xff09;和网络层&#xff08;L3&#xff09;。 L1&#xff1a;物理…

【设计模式】(一)设计模式概述

一、设计模式概述 设计模式&#xff08;Design pattern&#xff09;**是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结 在GOF编写的设计模式(可复用面向对象软件的基础)一书中说道: 本书涉及的设计模式并不描述新的或未经证实的设计&#xff0c;我们只收…

LeetCode34.在排序数组中查找元素的第一个和最后一个位置

题目 给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target&#xff0c;返回 [-1, -1]。 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。 示例 输入…

模型选择与评估

&#x1f6a9; 机器学习的一般流程包括&#xff1a;数据集的准备与预处理、搭建模型、模型训练、模型评估与应用。 在现实任务中&#xff0c;我们往往有多种学习算法可供选择&#xff0c;甚至对同一个学习算法&#xff0c;当使用不同的参数配置时&#xff0c;也会产生不同的模型…

Javascript:输入输出

目录 一.前言 二.正文 1.输出 2.输入 3.字面量 概念&#xff1a; 三.结语 一.前言 Javascript作为运行浏览器的语言&#xff0c;对于学习前端的同学来说十分重要&#xff0c;那么从现在开始我们将开始介绍有关 Javascript。 二.正文 1.输出 document.write() : 向body内…

新品齐发!小牛电动打造全场景高端化产品阵列!

2 月 29 日&#xff0c;全球智能城市出行品牌小牛电动发布“新世代性能旗舰”电摩NX、电自NXT&#xff0c;以及“全场景智驾越野电摩”X3三款新品。同时&#xff0c;与知名体育电竞俱乐部——JDG京东电子竞技俱乐部携手&#xff0c;打造“英雄的联盟”超级形象&#xff0c;引领…

扫码点餐多门店先付后餐小程序开发

多门店扫码点餐系统-先付后餐模式-公众号与小程序开源版 适用范围&#xff1a;适用于快销类餐饮&#xff0c;如早餐、面馆、快餐、零食小吃等&#xff0c;满足顾客快捷扫码点餐的需求。 该系统仅支持先付款后就餐的模式&#xff0c;不支持赊账或后付款服务。 核心功能&…

免费pr素材(Premiere创意彩色图形动画背景视频素材)下载

Premiere素材&#xff0c;10个创意彩色图形动画pr背景视频素材&#xff0c;Pr动态图形模板mogrt下载。 特点&#xff1a;Premiere Pro 2023或更高版本&#xff0c;超高清分辨率&#xff1a;38402160&#xff0c;每秒25帧的帧速率&#xff0c;包括教程视频。来自PR素材网&#x…

MDS500-16-ASEMI整流模块MDS500-16参数、封装、尺寸

编辑&#xff1a;ll MDS500-16-ASEMI整流模块MDS500-16参数、封装、尺寸 型号&#xff1a;MDS500-16 品牌&#xff1a;ASEMI 封装&#xff1a;M34 正向电流&#xff08;Id&#xff09;&#xff1a;500A 反向耐压&#xff08;VRRM&#xff09;&#xff1a;1600V 正向浪涌…

Amino PEG11 COOH,Amino-PEG11-acid,可在活化剂存在下与氨基反应

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;1616426-12-0&#xff0c;Amino-PEG11-acid&#xff0c;Amino PEG11 COOH&#xff0c;H2N-PEG11-CH2CH2COOH&#xff0c;氨基-PEG11-羧酸 一、基本信息 【产品简介】&#xff1a;Amino-PEG11 acid is a heterobifun…

探索Redis 6.0的新特性

Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的内存中数据结构存储系统&#xff0c;通常被用作缓存、消息队列和实时数据处理等场景。它的简单性、高性能以及丰富的数据结构支持使其成为了众多开发者和企业的首选。在Redis 6.0版本中&#xff0c;引入了一…

超越CPU和GPU:引领AI进化的LPU

什么是CPU CPU&#xff08;Central Processing Unit&#xff09;是由数十亿个晶体管构成的&#xff0c;可以拥有多个处理核心&#xff0c;通常被称为计算机的“大脑”。它对所有现代计算系统至关重要&#xff0c;因为它执行计算机和操作系统所需的命令和进程。CPU在决定程序运…

Leetcoder Day32| 贪心算法part05

763.划分字母区间 字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。 示例&#xff1a; 输入&#xff1a;S "ababcbacadefegdehijhklij"输出&#xff1a;[9,7…

【Leetcode每日一题】二分查找 - LCR 173. 点名(难度⭐)(24)

1. 题目解析 Leetcode题目链接&#xff1a;LCR 173. 点名 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 核心在于找到题目所给的连续数组中缺失的数字即可。 2.算法原理 在这个升序的数组中&#xff0c;我们发现&#xff1a; …