《UNIX网络编程 卷1:套接字联网API》学习笔记——名字与地址转换

域名系统

域名系统(DNS)主要用于主机名字与IP地址之间的映射。
主机名既可以是一个简单名字,例如 solaris 或 bsdi ,也可以是一个全限定域名(FQDN),例如 solaris.unpbook.com 。

资源记录

DNS中的条目称为资源记录(RR)。

  • A , A记录把一个主机名映射成一个32位的IPv4地址。
  • AAAA , 称为“四A”(quad A)记录的AAAA记录把一个主机名映射成一个128位的 IPv6 地址。
  • PTR, 称为“指针记录”的PTR记录把 IP 地址映射成主机名。
  • MX , MX记录把一个主机指定作为给定主机的“邮件交换器”。
  • CNAME , CNAME 代表“canonical name”(规范名字),它的常见用法是为常用的服务(例如 ftp 和 www)指派 CNAME 记录。

解析器和名字服务器

每个组织机构往往运行一个或多个名字服务器,它们通常就是所谓的 BIND(Berkeley Internet Name Domain 的简称) 程序。

在这里插入图片描述
解析器代码通过读取其系统相关配置文件确定本组织机构的名字服务器们的所在位置。

文件 /etc/resolv.conf 通常包含本地名字服务器主机的 IP 地址。

解析器使用 UDP 向本地名字服务器发出查询。

DNS 替代方法

不使用 DNS 也可能获取名字和地址信息。

常见的替代方法有静态主机文件(通常是 /etc/hosts 文件)、网络信息系统(Network Information System, NIS)以及轻权目录访问协议(Lightweight Directory Access Protocol, LDAP)。

gethostbyname 函数

#include <netdb.h>
struct hostent *gethostbyname(const char*hostname);
                                   返回:若成功则为非空指针,若出错则为NULL且设置 h_errno
struct hostent
{
	char *h_name;// 主机名
	char **h_aliases;// 别名列表
	int h_addrtype;
	int h_length;// IP地址个数
	char **h_addr_list;// IP地址列表
};

在这里插入图片描述
当发生错误时,它不设置 errno 变量,而是将全局整数变量 h_errno 设置为在头文件 <netdb.h>中定义的下列常值之一:

  • HOST_NOT_FOUND;
  • TRY_AGAIN;
  • NO_RECOVERY;
  • NO_DATA(等同于 NO_ADDRESS)。

NO_DATA 错误表示指定的名字有效。

gethostbyaddr 函数

#include <netdb.h>
struct hostent *gethostbyaddr(const char *addr, sock_len_t len, int family);
                                返回:若成功则为非空指针,若出错则为NULL且设置 h_errno 

gethostbyaddr 函数试图由一个二进制的 IP 地址找到相应的主机名,与 gethostbyname 的行为刚好相反。

getservbyname 和 getservbyport 函数

服务:提供某种功能
协议:以TCP或UDP方式进行服务提供
服务需基于某个传输协议,在某个指定端口提供服务

服务配置文件:/etc/services
但有些服务即使在此配置文件中配置了,但实际主机可能并未启用.
有些服务,实际起作用,但并没在此配置文件下进行配置.
此配置文件中的配置也无法保证一定和实际相符.
故,只能是提供一个参考价值.

#include <netdb.h>
struct servent* getservbyname(
	const char* servname, // 服务名
	const char* protoname);// 服务所用协议
                            
                            返回:若成功则为非空指针,若出错则为 NULL

本函数返回的非空指针指向如下的 servent 结构。

struct servent
{
	char *s_name;// 服务名
	char **s_aliases;// 别名列表
	int s_port;// 服务端口号,以网络字节序表示.后续可直接使用
	char *s_proto;// 服务所用协议
};

函数 getservbyport 用于根据给定端口号和可选协议查找相应服务。

#include <netdb.h>
struct servent *getservbyport(
	int port,// 服务端口号,需传递网络字节序的参数,可用htons
	const char *protoname);// 服务所用协议

                              返回:若成功则为非空指针,若出错则为 NULL

getaddrinfo 函数

#include <netdb.h>
int getaddrinfo(
	// 主机名/点分形式的IPv4,Ipv6地址
	const char *hostname,
	// 服务名/服务端口号
	const char *service,
	// 可以为NULL
	// 用于填入对期望返回信息类型的暗示
	const struct addrinfo *hints,
	struct addrinfo **result);

                                  返回:若成功则为0,若出错则为非0
struct addrinfo
{
	int ai_flags;
	int ai_family;
	int ai_socktype;
	int ai_protocol;
	char* ai_canonname;
	socklen_t ai_addrlen;
	struct sockaddr *ai_addr;
	struct addrinfo *ai_next;
};

hints 结构中调用者可以设置的成员有:

  • ai_flags (零个或多个或在一起的 AI_xxx);
  • ai_family (某个 AF_xxx值);
  • ai_socktype (某个 SOCK_xxx值);
  • ai_protocol 。

其中 ai_flags 成员可用的标志值及其含义如下:

  • AI_PASSIVE 套接字用于被动打开
  • AI_CANONNAME 返回主机的规范名字
  • AI_NUMERICHOST hostname必须是地址串
  • AI_NUMERICSERV service需为十进制端口号数串
  • AI_V4MAPPED 要求返回IPV6但没有IPV6地址时,也允许返回IPV4地址[会被映射到IPV6地址]
  • AI_ALL
  • AI_ADDRCONFIG

服务器进程使用getaddrinfo时,一般只指定service,同时hints中指定AI_PASSIVE,这样返回的struct sockaddr结构中IP部分类似INADDR_ANY[IPV4]/IN6ADDR_ANY_INIT取得的那样。

客户进程使用getaddrinfo获取用于套接字创建及本地绑定目的时,对主机名不设置下,同时hints中不含AI_PASSIVE,这样返回的struct sockaddr结构中IP部分类似0::1/127.0.0.1取得的那样。

struct sockaddr_storage 是一个套接字地址结构,大小可容纳IPV4/IPV6/域套接字等各类型地址对象,且满足它们的对齐限制。

gai_strerror 函数

#include <netdb.h>
const char *gai_strerror(int error);
                                     返回:指向错误描述消息字符串的指针

在这里插入图片描述

freeaddrinfo 函数

由 getaddrinfo 返回的所有存储空间都是动态获取的(如, 来自 malloc 调用),包括 addrindo 结构、ai_addr 结构和 ai_canonname 字符串。

这些存储空间通过调用 freeaddrinfo 返还给系统。

#include <netdb.h>
void freeaddrinfo(struct addrinfo *ai);

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

getaddrinfo 函数:IPv6

在这里插入图片描述

getnameinfo 函数

getnameinfo 和 getaddrinfo 的互补函数,它以一个套接字地址为参数,返回描述其中的主机的一个字符串和描述其中的服务的另一个字符串。

#include <netdb.h>
int getnameinfo(
	// 指向一个套接字地址结构
	const struct sockaddr* sockaddr,
	socklen_t addrlen,
	char *host,
	socklen_t hostlen,
	char *serv,
	socklen_t servlen,
	int flags);

                                   返回:若成功则为0,若出错则为非0

在这里插入图片描述

学习参考资料:

《UNIX网络编程 卷1:套接字联网API》 第3版
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值