getaddrinfo()函数详解
1. 概述IPv4中使用gethostbyname()函数完成主机名到地址解析,这个函数仅仅支持IPv4,且不允许调用者指定所需地址类型的任何信息,返回的结构只包含了用于存储IPv4地址的空间。IPv6中引入了getaddrinfo()的新API,它是协议无关的,既可用于IPv4也可用于IPv6。getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换,返回的是一个addrinfo的结构(列表)指针而不是一个地址清单。这些addrinfo结构随后可由套接口函数直接使用。如此以来,getaddrinfo函数把协议相关性安全隐藏在这个库函数内部。应用程序只要处理由getaddrinfo函数填写的套接口地址结构。该函数在 POSIX规范中定义了。2. 函数说明包含头文件 #include<netdb.h>函数原型 int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result );参数说明 hostname:一个主机名或者地址串(IPv4的点分十进制串或者IPv6的16进制串) service:服务名可以是十进制的端口号,也可以是已定义的服务名称,如ftp、http等 hints:可以是一个空指针,也可以是一个指向某个addrinfo结构体的指针,调用者在这个结构中填入关于期望返回的信息类型的暗示。举例来说:如果指定的服务既支持TCP也支持UDP,那么调用者可以把hints结构中的ai_socktype成员设置成SOCK_DGRAM使得返回的仅仅是适用于数据报套接口的信息。 result:本函数通过result指针参数返回一个指向addrinfo结构体链表的指针。 返回值:0——成功,非0——出错3. 参数设置在getaddrinfo函数之前通常需要对以下6个参数进行以下设置:nodename、servname、hints的ai_flags、ai_family、ai_socktype、ai_protocol。 在6项参数中,对函数影响最大的是nodename,sername和hints.ai_flag,而ai_family只是有地址为v4地址或v6地址的区别。ai_protocol一般是为0不作改动。getaddrinfo在实际使用中的几种常用参数设置 一般情况下,client/server编程中,server端调用bind(如果面向连接的还需要listen),client则不用掉bind函数,解析地址后直接connect(面向连接)或直接发送数据(无连接)。因此,比较常见的情况有 (1) 通常服务器端在调用getaddrinfo之前,ai_flags设置AI_PASSIVE,用于bind;主机名nodename通常会设置为NULL,返回通配地址[::]。 (2) 客户端调用getaddrinfo时,ai_flags一般不设置AI_PASSIVE,但是主机名nodename和服务名servname(更愿意称之为端口)则应该不为空。 (3) 当然,即使不设置AI_PASSIVE,取出的地址也并非不可以被bind,很多程序中ai_flags直接设置为0,即3个标志位都不设置,这种情况下只要hostname和servname设置的没有问题就可以正确bind。上述情况只是简单的client/server中的使用,但实际在使用getaddrinfo和参考国外开源代码的时候,曾遇到一些将servname(即端口)设为NULL的情况(当然,此时nodename必不为NULL,否则调用getaddrinfo会报错)。 以下分情况进行了测试: (1) 如果nodename是字符串型的IPv6地址,bind的时候会分配临时端口; (2) 如果nodename是本机名,servname为NULL,则根据操作系统的不同略有不同,本文仅在WinXP和Win2003上作了测试。a) WinXP系统(SP2)返回loopback地址[::1]b) Win2003则将本机的所有IPv6地址列表加以返回。因为通常一台IPv6主机都有可能不止一个IPv6地址,比如fe80::1(本机 loopback地址)、fe80::***的Link-Local地址、3ffe:***的全局地址等等。这种情况下调用getaddrinfo会将这些地址全部返回,调用者应该注意如何使用这些地址。另外要注意的是,对于fe80::的地址在绑定的时候必须标明接口地址,即使用 fe80::20d:60ff:fe78:51c2%4或fe80::1%1这样的地址格式,通过getaddrinfo直接取出fe80地址好像无法直接bind。4. 使用细节如果本函数返回成功,那么由result参数指向的变量已被填入一个指针,它指向的是由其中的ai_next成员串联起来的addrinfo结构链表。可以导致返回多个addrinfo结构的情形有以下2个:1. 如果与hostname参数关联的地址有多个,那么适用于所请求地址簇的每个地址都返回一个对应的结构。2. 如果service参数指定的服务支持多个套接口类型,那么每个套接口类型都可能返回一个对应的结构,具体取决于hints结构的ai_socktype成员。我们必须先分配一个hints结构,把它清零后填写需要的字段,再调用getaddrinfo,然后遍历一个链表逐个尝试每个返回地址。getaddrinfo解决了把主机名和服务名转换成套接口地址结构的问题。其中,如果getaddrinfo出错,那么返回一个非0的错误值。 #include<netdb.h> const char *gai_strerror( int error ); 该函数以getaddrinfo返回的非0错误值的名字和含义为他的唯一参数,返回一个指向对应的出错信息串的指针。由getaddrinfo返回的所有存储空间都是动态获取的,这些存储空间必须通过调用freeaddrinfo返回给系统。 #include< netdb.h > void freeaddrinfo( struct addrinfo *ai ); ai参数应指向由getaddrinfo返回的第一个addrinfo结构。这个连表中的所有结构以及它们指向的任何动态存储空间都被释放掉
addrinfo结构
结构 固定的参数
typedef struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
char* ai_canonname;
struct sockaddr* ai_addr;
struct addrinfo* ai_next;
} ai_addrlen must be zero or a null pointer
ai_canonname must be zero or a null pointer
ai_addr must be zero or a null pointer
ai_next must be zero or a null pointer
可以改动的参数
ai_flags:AI_PASSIVE,AI_CANONNAME,AI_NUMERICHOST
ai_family: AF_INET,AF_INET6
ai_socktype:SOCK_STREAM,SOCK_DGRAM
ai_protocol:IPPROTO_IP, IPPROTO_IPV4, IPPROTO_IPV6 etc.3 参数说明
在getaddrinfo函数之前通常需要对以下6个参数进行以下设置:nodename、servname、hints的ai_flags、ai_family、ai_socktype、ai_protocol
在6项参数中,对函数影响最大的是nodename,sername和hints.ai_flag
而ai_family只是有地址为v4地址或v6地址的区别。而ai_protocol一般是为0不作改动。
其中ai_flags、ai_family、ai_socktype说明如下:
参数 取值 值 说明
ai_family AF_INET 2 IPv4
AF_INET6 23 IPv6
AF_UNSPEC 0 协议无关
ai_protocol IPPROTO_IP 0 IP协议
IPPROTO_IPV4 4 IPv4
IPPROTO_IPV6 41 IPv6
IPPROTO_UDP 17 UDP
IPPROTO_TCP 6 TCP
ai_socktype SOCK_STREAM 1 流
SOCK_DGRAM 2 数据报
ai_flags AI_PASSIVE 1 被动的,用于bind,通常用于server socket
AI_CANONNAME 2AI_NUMERICHOST 4 地址为数字串对于ai_flags值的说明:
AI_NUMERICHOST AI_CANONNAME AI_PASSIVE
0/1 0/1 0/1如上表所示,ai_flagsde值范围为0~7,取决于程序如何设置3个标志位,比如设置ai_flags为“AI_PASSIVE|AI_CANONNAME”,ai_flags值就为3。三个参数的含义分别为:
(1)AI_PASSIVE当此标志置位时,表示调用者将在bind()函数调用中使用返回的地址结构。当此标志不置位时,表示将在connect()函数调用中使用。
当节点名位NULL,且此标志置位,则返回的地址将是通配地址。
如果节点名NULL,且此标志不置位,则返回的地址将是回环地址。
(2)AI_CANNONAME当此标志置位时,在函数所返回的第一个addrinfo结构中的ai_cannoname成员中,应该包含一个以空字符结尾的字符串,字符串的内容是节点名的正规名。
(3)AI_NUMERICHOST当此标志置位时,此标志表示调用中的节点名必须是一个数字地址字符串。
代码Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <string.h> int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "Usage: %s hostname\n", argv[1]); exit(1); }struct addrinfo *answer, hint, *curr; char ipstr[16]; bzero(&hint, sizeof(hint)); hint.ai_family = AF_INET; hint.ai_socktype = SOCK_STREAM;int ret = getaddrinfo(argv[1], NULL, &hint, &answer); if (ret != 0) { fprintf(stderr,"getaddrinfo: &s\n", gai_strerror(ret)); exit(1); }for (curr = answer; curr != NULL; curr = curr->ai_next) { inet_ntop(AF_INET, &(((struct sockaddr_in *)(curr->ai_addr))->sin_addr), ipstr, 16); printf("%s\n", ipstr); }freeaddrinfo(answer); exit(0); }
转载于:https://www.cnblogs.com/zhangsf/p/3145552.html
getaddrinfo()函数详解相关推荐
- getaddrinfo函数详解
有这样一个C/S程序,server提供一个叫做ruptime的服务,功能是当有客户端连接时调用uptime程序,并将结果发送到client.可是现在的问题是,这个服务系统本来是没有的,所以调用geta ...
- C语言网络编程:accept函数详解
文章目录 前言 函数描述 代码实例 如何得到客户端的IP 和 端口号 前言 当使用tcp服务器使用socket创建通信文件描述符,bind绑定了文件描述符,服务器ip和端口号,listen将服务器端的 ...
- 【FFmpeg】函数详解(三)
FFmpeg函数详解 14.av_write_frame 15.av_interleaved_write_frame 16.av_write_trailer 17.avio_close 18.av_i ...
- 【FFmpeg】函数详解(二)
FFmpeg函数详解 9.av_dump_format 10.avio_open 11.avformat_write_header 12.avcodec_send_frame 13.avcodec_r ...
- 【FFmpeg】函数详解(一)
FFmpeg函数详解 一.错误码相关 1.AVERROR 2.av_strerror 3.其他错误码解释 二.编解码 1.获取编解码器 2.申请.释放上下文环境 3.打开编码器avcodec_open ...
- 【ES6】Generator函数详解
[ES6]Generator函数详解 一.Generator函数简介 基本概念 函数写法 yield关键字介绍 二.next方法的参数 三.for...of循环 四.关于普通throw()与Gener ...
- mysql的聚合函数综合案例_MySQL常用聚合函数详解
一.AVG AVG(col) 返回指定列的平均值 二.COUNT COUNT(col) 返回指定列中非NULL值的个数 三.MIN/MAX MIN(col):返回指定列的最小值 MAX(col):返回 ...
- python平方数迭代器_对python中的高效迭代器函数详解
python中内置的库中有个itertools,可以满足我们在编程中绝大多数需要迭代的场合,当然也可以自己造轮子,但是有现成的好用的轮子不妨也学习一下,看哪个用的顺手~ 首先还是要先import一下: ...
- python基础知识~ 函数详解2
python~函数详解2 1 生成器函数 定义 如果函数有yield这个关键字,就是生成器函数.生成器函数() 获取的是生成器,不执行函数 须知 yield和return一样,都可以返回数 ...
最新文章
- python加载图片的方法_python从网络读取图片并直接进行处理的方法
- Graph2Vec在XFL论文中提及的用处
- springCloud全家桶
- PCB工艺的一些小原则
- VTK:PolyData之DijkstraGraphGeodesicPath
- ecshop2.71 lbi库文件添加流程
- NetBeans 7.2 beta:更快,更有用
- 程序员编程艺术第十一章:最长公共子序列(LCS)问题
- csv中包含多余换行符_Python3爬虫之猫眼电影TOP100(requests、lxml、Xpath、CSV)
- 解决安装MarkupSafe安装 from setuptools import Feature 报错ImportError: cannot import name ‘Feature‘
- ansible 建 kubernetes 证书签名请求_Java中的微信支付(2):API V3 微信平台证书的获取与刷新...
- 华为G610开机第一屏G3替换教程
- TMR 传感器的原理及应用
- 2021年一季度口腔护理行业网络关注度分析报告
- 从入门到放弃:微信小程序入门个人指南Day 4
- Spring Security--基于注解访问控制 @Secured@PreAuthorize
- unity物体自身轴旋转_Unity 中物体的旋转
- HTML5的学习资料(开发设计原则)
- BlogsToWordPress v16.9 – 将(新版)百度空间,网易163,新浪sina,QQ空间,人人网,CSDN,搜狐Sohu,博客大巴Blogbus,天涯博客,点点轻博客等博客搬家到Wor
- 十大家用智能监控摄像头品牌排名
热门文章
- 你没听说过的Go语言惊人优点
- python添加数组元素_Python列表附录–如何向数组添加元素,并附带示例说明
- vue css 应用变量_如何使用CSS Grid和CSS变量快速为应用创建原型
- 本地navicat连接阿里云数据库
- Python组合数据类型之序列类型
- 优秀的Java程序员应具备哪些编程技术?
- 什么是安全测试?哪些阶段需要安全测试?
- 微软推出Windows XP/Server 2003紧急安全补丁:修复远程桌面CVE-2019-0708漏洞
- 服务器ldap认证配置
- JavaScript深入理解对象方法——Object.entries()