IPv4中使用gethostbyname()函数完成主机名到地址解析,但是该API不允许调用者指定所需地址类型的任何信息,返回的结构只包含 了用于存储IPv4地址的空间。为了解决该问题,IPv6中引入了getaddrinfo()的新API,它是协议无关的,既可用于IPv4也可用于 IPv6。调用该函数会获得一个addrinfo结构的列表,调用的返回值是addrinfo的结构(列表)指针。

本文结合在WinowsXP和Windows2003 Server上使用该函数的经验,对getaddrinfo函数和addrinfo数据结构进行介绍,并对其参数的设置加以讨论,主要包括 nodename和servname的取值对返回值的影响,hints成员变量的设置对返回值的影响等。

可能有不完全或不准确的地方,欢迎大家讨论并指出。

1.getaddrinfo函数原型

函数

参数说明

int getaddrinfo(

const char* nodename

const char* servname,

const struct addrinfo* hints,//

struct addrinfo** res

);

nodename:节点名可以是主机名,也可以是数字地址。(IPV4的10进点分,或是IPV6的16进制)

servname:包含十进制数的端口号或服务名如(ftp,http)

hints:是一个空指针或指向一个addrinfo结构的指针,由调用者填写关于它所想返回的信息类型的线索。

res:存放返回addrinfo结构链表的指针

Getaddrinfo提供独立于协议的名称解析。

函数的前两个参数分别是节点名和服务名。节点名可以是主机名,也可以是地址串(IPv4的点分十进制数表示或IPv6的十六进制数字串)。服务名可以是十进制的端口号,也可以是已定义的服务名称,如ftp、http等。注意:其中节点名和服务名都是可选项,即节点名或服务名可以为NULL,此时调用的结果将取缺省设置,后面将详细讨论。

函数的第三个参数hints是addrinfo结构的指针,由调用者填写关于它所想返回的信息类型的线索。函数的返回值是一个指向addrinfo结构的链表指针res。

2.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

2

 

AI_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当此标志置位时,此标志表示调用中的节点名必须是一个数字地址字符串。

4.实际使用的几种常用设置

一般情况下,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,则根据操作系统的不同略有不同

注意点是: 这个函数,说起来,是get ,但是其实可以理解为creat 或者是理解为构建 。 因为你可以随意构建自己的地址结构addrinfo。

如 果本函数返回成功,那么由result参数指向的变量已被填入一个指针,它指向的是由其中的ai_next成员串联起来的addrinfo结构链表。可以 导致返回多个addrinfo结构的情形有以下2个:
    1.    如果与hostname参数关联的地址有多个,那么适用于所请求地址簇的每个地址都返回一个对应的结构。
    2.    如果service参数指定的服务支持多个套接口类型,那么每个套接口类型都可能返回一个对应的结构,具体取决于hints结构的ai_socktype 成员。

我们必须先分配一个hints结构,把它清零后填写需要的字段,再调用getaddrinfo然后遍历一个链表逐个尝试每个返回地 址。

getaddrinfo解决了把主机名和服务名转换成套接口地址结构的问题。

其中,如果getaddrinfo出 错,那么返回一个非0的错误值。

官方说明的链接:http://www.kernel.org/doc/man-pages/online/pages/man3/gai_strerror.3.html

很详细。

getaddrinfo()详解的更多相关文章

  1. getaddrinfo详解

    #include <sys/socket.h> #include <netdb.h> int getaddrinfo(const char *restrict nodename ...

  2. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  3. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  4. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

  5. Java 字符串格式化详解

    Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...

  6. Android Notification 详解(一)——基本操作

    Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...

  7. Android Notification 详解——基本操作

    Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...

  8. Git初探--笔记整理和Git命令详解

    几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...

  9. Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)

    Android XML shape 标签使用详解   一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...

随机推荐

  1. SQL学习笔记之MySQL中真假“utf8” 问题

    0x00 MySQL中UTF8报错 最近我遇到了一个 bug,我试着通过 Rails 在以“utf8”编码的 MariaDB 中保存一个 UTF-8 字符串,然后出现了一个离奇的错误: Incorre ...

  2. 为什么@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})

    Spring Boot会自动根据jar包的依赖来自动配置项目,例如当你项目下面有HSQLDB的依赖,Spring Boot会自动创建默认的内存数据库的数据源DataSource, 但我们使用Mybat ...

  3. 20145307第二次JAVA学习实验报告

    20145307<Java程序设计>实验报告二:Java面向对象程序设计 实验要求 1.初步掌握单元测试和TDD 2.理解并掌握面向对象三要素:封装.继承.多态 3.初步掌握UML建模 4 ...

  4. 20145321 《Java程序设计》第一周学习总结

    20145321 <Java程序设计>第1周学习总结 教材学习内容总结 第一章 1.三大平台:Java SE.Java EE .Java ME 2.Java SE:由JVM.JRE.JDK ...

  5. [BZOJ2282]消防

    Description 某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000). 这个国家的人对火焰有超越宇宙的热情,所以这个国家 ...

  6. Android 图形基础类Rect,扎实基础助腾飞

    转载请注明出处:王亟亟的大牛之路 上周把"垃圾桶动画写完了",然后这礼拜寻思着学习点啥,脑子闷逼了大半天,然后就找了点基础源码读读,把看的经历分享给大家. 先安利:https:// ...

  7. ubuntu install git vim Plug manage

    在UBUNTU采用163或是阿里云来更新源,最新的更新源地址可以在网上查阅, 阿里源 deb http://mirrors.aliyun.com/ubuntu/ bionic main restric ...

  8. 数据库访问辅助类SqlHelper

    程序访问数据库需要进行的操作有创建与某个指定数据库的连接, 然后打开创建好的连接,创建执行指令(也就是sql执行代码), 最后执行指令,关闭创建的连接,释放资源. ado.net是一组用于和数据源进行 ...

  9. url传递数据类型

    php中传递数据,get或post方式为啥用字符串传递,为什么不能直接用数组形式,用的话可以吗

  10. 简化Kubernetes应用部署工具-Helm

    [编者的话]微服务和容器化给复杂应用部署与管理带来了极大的挑战.Helm是目前Kubernetes服务编排领域的唯一开源子项目,做为Kubernetes应用的一个包管理工具,可理解为Kubernete ...