第3章 关于名称和地址族

3.1 将名称映射到数字

       socket API的大多数实现允许访问把名称映射到其他信息(包括Interenet地址)的名称

服务(name service)。可以把名称(www.baidu.com)映射到Internet地址,也可以把服务

(例如:应答echo)的名称映射到端口号。

       解析:把名称映射到数值(地址或端口号)的过程。有很多种方式,一些涉及在后天与

其它系统交互,另一些严格在本地进行。

       名称服务并不是使TCP/IP工作所必需的。名称只是提供一个间接层次,主机名服务可以访问

广泛来源的信息,主要是DNS(Domain Name System)和本地配置数据库。

       DNS是一种分布式数据库,用于把像www.baidu.com这样的Domain name 映射到Internet地址

及其他信息。DNS协议允许连接到Internet的主机使用TCP或UDP从该数据库中检索信息。

       本地配置数据库一般是用于名称-Internet地址映射的特定于操作系统的机

3.1.1 访问名称服务

      主机名称和服务名称映射到一个地址。

       #include <sys/socket.h>

       #include <netdb.h>        //addrinfo

       int getaddrinfo(const char *restrict host,

                                   const char *restrict service,

                                   const struct addrinfo *restrict hint,

                                   struct addrinfo **restrict res);

                     返回值:若成功返回0,出错返回非0错误码

       需要提供主机名称或地址,服务名称或端口号。若只提供一个名字另一个必须为空指针

主机名称可以是一个节点名点分十进制法表示的主机地址

       第三个参数是要返回的信息的种类,可以使用一个可选的hint来选择地址hint是一个过滤

地址的模版。仅使用ai_family, ai_flag, ai_protocol和ai_socktype字段。其它整数字段必须

设为0并且指针字段为空。它表明系统调用者对那一类端点感兴趣。ai_socktypeai_protocol

设为0表示我们希望接受所有可能的数据。若hint为NULL:系统被期望处理这种情况,等价于ai_famliy

设为AF_UNSPEC允许返回任何地址包括AF_INET和AF_INET6),其它字段为0

 

       ai_flags中所用的标志用来指定如何处理地址和名字

ai_flags                 描述

 

AI_ADDRCONFIG       查询配置的地址类型(IPv4或IPv6)。设置此标志仅当系统具有特定的地址配置

                            的接口时,getaddrinfo()才会返回该地址族的地址。因此仅当系统具有IPv4的接口

                            时,才会返回IPv4地址,对于IPv6同样。

AI_ALL                查询IPv4和IPv6地址(仅用于AI_V4MAPPED)

AI_CANONNAME       需要一个规范名(而不是主机名),类似于一个名称可以解析为许多数字地址一样。

                            可以把多个名称解析成一个IP地址。不过,其中有一个名称被解析为正式(规范)

                            名称。

AI_NUMERICHOST     以数字格式返回主机地址。如果host不是一个具有有效的数字地址格式的字符串,

                            这个标志导致返回一个错误。

AI_NUMERICSERV     以端口号返回服务

AI_PASSIVE        套接字地址用于监听绑定。若后host为NULL,任何返回的addrinfo都将把它们的地址

                            设置为合适的“任意”常量INADDR_ANY(IPv4)或IN6ADDR_ANY_INIT(IPv6).

AI_V4MAPPED           如果没有找到IPv6地址,则返回映射到IPv6格式的IPv4地址。如果ai_family为

                            AF_INET6,并且没有找到匹配的IPv6地址,那么getaddrinfo()返回IPv4映射的IPv6

                            地址。仅支持IPv4和IPv6主机之间有限的互操作性。

第四个参数是存储一个指向包含结果的链表的指针

 

       函数getaddrinfo返回一个结构addrinfo的链表,使用freeaddrinfo释放一个或多个结构

这取决于用ai_next字段链接起来的结构多少。

       addrinfo至少包含:

       struct addrinfo {

              int                        ai_flags;         /* customize behavior */

              int                        ai_family;              /* address family */

              int                        ai_socktype;    /* socket type */

              int                        ai_protocol;    /* protocol */

              socklen_t        ai_addrlen;            /* length in bytes of address*/

              sturct sockaddr *ai_addr;              /* address */

              char               *ai_canonname      /* canonical name of host */

              struct addrinfo       *ai_next;        /* next in list */

              ...

       }

       为什么使用一个链表第一对于主机和服务的每种组合,可能有地址族(v4或v6)和

套接字类型/协议(流tcp或数据包udp)的多种不同组合表示可能端口。例如:“server.example.net”

可能具有在v4/tcpv6/udP上的端口1001上进行“垃圾邮件”服务侦听的多个实例。getaddrinfo

可以返回这两者。第二主机名称可以映射到多个ip地址

 

       两个辅助函数:

       #include <sys/socket.h>

       #include <netdb.h>

       void freeaddrinfo(struct addrinfo *addrlist);

 

       #include <netdb.h>

       const char *gai_strerror(int errorcode);

       如果,getaddrinfo失败不使用perror或strerror生成错误信息而是用gai_strerror将返回的错误码转换为

错误信息。

 

       函数getnameinfo地址转换成主机名或服务名Internet地址获取主机名称

       #include <sys/socket.h>

       #include <netdb.h>

 

       int getnameinfo(const struct sockaddr *restrict addr,

                                   socklen_t alen, char *restrict host,

                                   socklen_t hostlen, char *restrict service,

                                   socklen_t servlen, unsinged int flags);

套接字地址(addr)被转换成主机名或服务名。若host非空,它指向一个长度为hostlen字节的缓冲

区用于存储返回的主机名。若service非空,它指向一个长度为servlen字节的缓冲区用于存储返回的

服务名。

flags                     描述

NI_DGRAM          服务基于数据报非基于流

NI_NAMEREQD          如果找不到主机名称,将其作为一个错误对待

NI_NOFQDN        对于本地主机,仅返回完全限定域名的字节名字部分

NI_NUMERICHOST     以数字形式而非名字返回主机地址

NI_NUMERICSERV     以数字形式非名字返回服务地址(端口号)

 

       程序需要知道自己的主机名称,使用gethostname。它接受受一个缓冲区和缓冲区长度,并把运行

调用程序的主机的名称复制到给定的缓冲区。

       #include <unistd.h>

       int gethostname(char *namebuf, size_t buflength);

若缓冲区长度足够大,通过namebuf返回的字符串以null结尾。若缓冲区不够,则没有指定通过namebuf

返回的字符串是否以null结尾。

       最大主机长度为HOST_NAME_MAX,不同主机有不同长度。hostname命令可以获取和设置主机名。

 

       3.1.2 其它的地址查询

       这些函数返回的网络配置信息可能存放在许多地方,例如:保存在静态文件中(如:/etc/

hosts, /etc/serviecs等),或者在命名服务管理(如:DNS, NIS(Network Information Service))。

这些函数都可以访问它们。

 

       调用gethostent可以找到给定计算机的主机信息

       #include <netdb.h>

       struct hostent *gethostent(void);

                            返回值: 成功返回指针,出错返回NULL

       void sethostnet(int stayopen);

       void endhostent(void);

 

       如果主机数据文件没有打开,gethostent会打开它。函数gethostent返回文件的下一个条目。

函数sethostent会打开文件,如果文件已经被打开,那么将其回绕。函数endhostent关闭文件。

       gethostent返回时,得到一个指向hostent结构的指针,该结构可能包含一个静态的数据缓冲区。

每次调用gethostent将会覆盖这个缓冲区。hostent至少包含:

       struct hostent {

              char  *h_name;            /* name of host */

              char **h_aliases;    /* pointer to alternate host name arry */

              int    h_addrtype; /* address type */

              int      h_length;   /* length in bytes of address */

              char **h_addr_list; /* pointer to array of network address */

       };

返回的地址为网络字节顺序。

原文地址:https://www.cnblogs.com/hancm/p/3668356.html