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

😁博客主页😁:🚀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.hqwc.cn/news/501583.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

生成式 AI - Diffusion 模型的数学原理(5)

来自 论文《 Denoising Diffusion Probabilistic Model》&#xff08;DDPM&#xff09; 论文链接&#xff1a; https://arxiv.org/abs/2006.11239 Hung-yi Lee 课件整理 讲到这里还没有解决的问题是&#xff0c;为什么这里还要多加一个噪声。Denoise模型算出来的是高斯分布的均…

【Leetcode每日一刷】哈希表|纲领、242.有效的字母异位词、349. 两个数组的交集

纲领 &#x1f517;代码随想录理论部分 关于哈希表这个数据结构就不再重复讲了&#xff0c;下面对几个关键点记录一下&#xff1a; 哈希碰撞 解决方法1&#xff1a;拉链法 解决方法2&#xff1a;线性探测法 下面针对做题要用到的三种结构讲一下&#xff08;也是重复造轮子了…

Spring AI上架,打造专属业务大模型,AI开发再也不是难事!

Spring AI 来了 Spring AI 是 AI 工程师的一个应用框架&#xff0c;它提供了一个友好的 API 和开发 AI 应用的抽象&#xff0c;旨在简化 AI 应用的开发工序。 提供对常见模型的接入能力&#xff0c;目前已经上架 https://start.spring.io/&#xff0c;提供大家测试访问。&…

Docker技术概论(1):Docker与虚拟化技术比较

Docker技术概论&#xff08;1&#xff09; Docker与虚拟化技术比较 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https:…

cpp基础学习笔记03:类型转换

static_cast 静态转换 用于类层次结构中基类和派生类之间指针或者引用的转换。up-casting (把派生类的指针或引用转换成基类的指针或者引用表示)是安全的&#xff1b;down-casting(把基类指针或引用转换成子类的指针或者引用)是不安全的。用于基本数据类型之间的转换&#xff…

XUbuntu22.04之如何找到.so库所在的软件包?(二百一十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

JVM内存模型深度剖析和优化

JVM内存模型深度剖析和优化 Java语言的跨平台性 问题: Java语言的跨平台性是如何做到的 通过不同操作系统平台的JVM版本&#xff0c;Linux和Windows的JVM版本各不相同Java是跨平台解释性语言&#xff0c;可以在不同的操作系统运行&#xff0c;JVM从软件层面屏蔽不同操作系统在…

JOSEF约瑟 JZS-7G-42 AC220V静态可调延时中间继电器 端子式导轨安装15ms-10s

系列型号&#xff1a;JZS-7G-57端子排延时中间继电器&#xff1b;JZS-7G-42X端子排延时中间继电器&#xff1b;JZS-7G-22X端子排延时中间继电器&#xff1b;JZS-7G-21端子排延时中间继电器&#xff1b;JZS-7G-41端子排延时中间继电器&#xff1b;JZS-7G-51端子排延时中间继电器…

大数据可视化python01

import pandas as pd import matplotlib.pyplot as plt# 设置中文改写字体 plt.rcParams[font.sans-serif] [SimHei]# 读取数据 data pd.read_csv(C:/Users/wzf/Desktop/读取数据进行数据可视化练习/实训作业练习/瓜果类单位面积产量.csv ,encoding utf-8)#输出 print(data)…

Docker Swarm全解析:实现微服务高可用与故障转移的秘密武器

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Docker入门到精通》 《k8s入门到实战》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、基本概念和介绍 1、Docker Swarm 是什么&#xff0c;它与 …

#stm学习总结 (二十八)硬件随机数实验

28.1 随机数发生器简介 STM32F407 自带了硬件随机数发生器&#xff08;RNG&#xff09;&#xff0c;RNG 处理器是一个以连续模拟噪声为基础的随机数发生器&#xff0c;在主机读数时提供一个 32 位的随机数。 28.1.1 RNG 框图 STM32F407 的随机数发生器&#xff08;RNG&#x…

3dmax corona渲染器和vray渲染器哪个好?

Corona和Vray这两个渲染器都很不错&#xff0c;每个都有自己的优点和适用的情况&#xff0c;所以很难说哪个更好。 下面我简单给你对比一下&#xff1a; 1、操作界面&#xff1a;Vray的界面比较多&#xff0c;参数设置也复杂一点&#xff0c;初学者可能会觉得有点难上手。但C…