UNIX网络编程读书笔记:名字与地址转换
概述
在名字和数值地址间进行转换的函数:
gethostbyname和gethostbyaddr:在主机名字与IPv4地址之间进行转换。仅仅支持IPv4.
getservbyname和getservbyport:在服务名字和端口号之间进行转换。
getaddrinfo和getnameinfo:用于主机名字和IP地址之间以及服务名字和端口号之间的转换。(这两个函数是协议无关的)
域名系统
域名系统(Domain Name System,简称DNS)主要用于主机名字和IP地址之间的映射。
资源记录
DNS中的条目称为资源记录(resource record,简称RR)。
RR类型:
A A记录把一个主机名映射成一个32位的IPv4地址。
AAAA AAAA记录把一个主机名映射成一个128位的IPv6地址。
PTR 称为“指针记录(pointer record)”,它把IP地址映射成主机名。
解析器和名字服务器
每个组织机构往往运行一个或多个名字服务器(name server),它们通常就是所谓的BIND(Berkeley Internet Name Domain)程序。应用程序通过调用称为解析器(resolver)的函数库中的函数接触DNS服务器。常见的解析器函数是gethostbyname和gethostbyaddr:前者把主机名映射成IPv4地址,后者则执行相反的映射。
下图展示了应用进程、解析器和名字服务器之间的一个典型关系。
解析器代码通过读取其系统相关配置文件确定本组织机构的名字服务器们(为可靠和冗余的目的,大多数组织机构运行多个名字服务器)的所在位置。文件/etc/resolv.conf通常包含本地名字服务器主机的IP地址。
DNS替代方法
不使用DNS也可能获取名字和地址信息。常用的替代方法有静态主机文件(通常是/etc/hosts文件)、网络信息系统(Network Information System,简称NIS)以及轻权目录访问协议(Lightweight Directory Access Protocol,简称LDAP)。
gethostbyname函数
查找主机名最基本的函数是gethostbyname。如果调用成功,它就返回一个指向hostent结构的指针,该结构中含有所查找主机的所有IPv4地址。这个函数的局限是只能返回IPv4地址,而getaddrinfo函数能够同时处理IPv4地址和IPv6地址。
#include <netdb.h>
struct hostent *gethostbyname(const char *hostname);
返回值:非空指针——成功;空指针——出错,同时设置h_errno
本函数返回的非空指针指向如下的hostent结构:
struct hostent {
char *h_name; /* official(canonical) name of host */
char **h_aliases; /* pointer to array of pointers to alias names */
int h_addrtype; /* host address type: AF_INET */
int h_length; /* length of address: 4 */
char **h_addr_list; /* ptr to array of ptrs with IPv4 addrs */
};
gethostbyname与其他套接口函数的不同之处在于:当发生错误时,它不设置errno变量,而是将全局整数变量h_errno设置在头文件<netdb.h>中定义的下列常值之一:
HOST_NOT_FOUND
TRY_AGAIN
NO_RECOVERY
NO_DATA(等同于NO_ADDRESS)
多数解析器提供名为hstrerror的函数,它以某个h_errno值作为唯一的参数,返回的是一个const char *指针,指向相应错误的说明。
gethostbyaddr函数
gethostbyaddr函数试图由一个二进制IP地址找到相应的主机名,与gethostbyname的行为刚好相反。
#include <netdb.h>
struct hostent *gethostbyaddr(const char *addr, socklen_t len, int family);
返回值:非空指针——成功;空指针——出错,同时设置h_errno
本函数返回一个同样指向hostent结构的指针。
addr参数实际上不是char *类型,而是一个指向存放IPv4地址的某个in_addr结构的指针;
len参数是这个结构的大小:对于IPv4地址为4;
family参数为AF_INET。
getservbyname函数
服务也通常靠名字来认知。如果我们在程序代码中通过其名字而不是端口号来指代一个服务,而且从名字到端口号的映射关系保存在一个文件中(通常是/etc/services),那么即使端口号发生变动,我们需修改的仅仅是/etc/services文件中的某一行,而不必重新编译应用程序。
getservbyname函数用于根据给定的名字查找相应服务。
#include <netdb.h>
struct servent *getservbyname(const char *servname, const char *protoname);
返回:非空指针——成功;空指针——出错
本函数返回的非空指针指向如下的servent结构:
struct servent {
char *s_name; /* official service name */
char **s_aliases; /* alias list */
int s_port; /* port number, network-byte order */
char *s_proto; /* protocol to use */
};
服务名参数servname必须指定。如果同时指定了协议(即protoname参数为非空指针),那么指定服务必须有匹配的协议。有些因特网服务既用TCP也用UDP提供(例如DNS),其他因特网服务则仅仅支持单个协议(例如FTP要求使用TCP)。如果protoname未指定而servname指定服务支持多个协议,那么返回哪个端口号取决于实现。
servent结构中我们关心的主要是端口号。既然端口号是以网络字节序返回的,把它存放到套接口地址结构时绝不能调用htons。
本函数的典型调用如下:
struct servent *sptr; sptr = getservbyname("domain", "udp");
sptr = getservbyname("ftp", "tcp");
getservbyport函数
getservbyport函数用于根据给定端口号和可选协议查找相应服务。
#include <netdb.h>
struct servent *getservbyport(int port, const char *protoname);
返回:非空指针——成功;空指针——出错
port参数的值必须为网络字节序。本函数的典型调用如下:
struct servent *sptr; sptr = getservbyport(htons(53), "udp");
sptr = getservbyport(htons(21), "tcp");
getaddrinfo函数
getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换,它解决了把主机名和服务名转换成套接口地址结构的问题,返回的是一个sockaddr结构的链表而不是一个地址清单。这些sockaddr结构随后可由套接口函数直接使用。
#include <netdb.h>
int getaddrinfo(const char *hostname, const char *service,
const struct addrinfo *hints, struct addrinfo **result);
返回:0——成功;非0——出错
本函数通过result指针参数返回一个指向addrinfo结构链表的指针,而addrinfo结构定义在头文件<netdb.h>中:
struct addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
int ai_family; /* AF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
socklen_t ai_addrlen; /* length of ai_addr */
char *ai_canonname; /* ptr to canonical name for host */
struct sockaddr *ai_addr; /* ptr to socket address structure */
struct addrinfo *ai_next; /* ptr to next structure in linked list */
};
其中,
hostname参数是一个主机名或地址串(IPv4的点分十进制数串或IPv6的十六进制数串)。
service参数是一个服务名或十进制端口号数串。
hints参数可以是一个空指针,也可以是一个指向某个addrinfo结构的指针,调用者在这个结构中填入关于期望返回的信息类型的暗示。
hints结构中调用者可以设置的成员有:
- ai_flags(零个或多个在一起的AI_xxx值)
- ai_family(某个AF_xxx值)
- ai_socktype(某个SOCK_xxx值)
- ai_protocol
其中ai_flags成员可用的标志值及其含义如下:
AI_PASSIVE 套接口将用于被动打开。
AI_CANONNAME 告知getaddrinfo函数返回主机的规范名字。
AI_NUMERICHOST 防止任何类型的名字到地址映射;hostname参数必须是一个地址串。
AI_NUMERICSERV 防止任何类型的名字到服务映射;service参数必须是一个十进制端口号数串。
AI_V4MAPPED 如果同时指定ai_family成员的值为AF_INET6, 那么如果没有可用的AAAA记录,就返回与A记录对应的IPv4映射的IPv6地址。
AI_ALL 如果同时指定AI_V4MAPPED标志,那么除了返回与AAAA记录对应的IPv6地址外,还返回与A记录对应的IPv4映射的IPv6地址。
AI_ADDRCONFIG 按照所在主机的配置选择返回地址类型,也就是只查找与所在主机回馈接口以外的网络接口配置的IP地址版本一致的地址。
如果hints参数是一个空指针,本函数就假设ai_flags、ai_sokctype和ai_protocol的值均为0,ai_family的值为AF_UNSPEC。
如果本函数返回成功(0),那么由result参数指向的变量已被填入一个指针,它指向的是由其中的ai_next成员串接起来的addrinfo结构链表。可导致返回多个addrinfo结构的情形有以下两个:
如果与hostname参数关联的地址有多个,那么适用于所请求地址族(可通过hints结构的ai_family成员设置)的每个地址都返回一个对应的结构。
如果service参数指定的服务支持多个套接口类型,那么每个套接口类型都可能返回一个对应的结构,具体取决于hints结构的ai_socktype成员。
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——出错
sockaddr指向一个套接口地址结构。
待返回的2个直观可读的字符串由调用者预先分配存储空间:host和hostlen指定主机字符串;serv和servlen指定服务字符串。如果调用者不想返回主机字符串,那就指定hostlen为0。同样,把servlen指定为0就是不想返回服务字符串。头文件<netdb.h>中定义了2个常值用于分配这两个存储空间:NI_MAXHOST给出主机字符串存储空间的最大长度,值为1025;NI_MAXSERV给出服务字符串存储空间的最大长度,值为32.
6个可指定的标志flags,用于改变getnameinfo的操作:
常值 | 说明 |
NI_DGRAM NI_NAMEREQD NI_NOFQDN NI_NUMERICHOST NI_NUMERICSCOPE NI_NUMERICSERV |
数据报服务 若不能从地址解析出名字则返回错误 只返回FQDN的主机名部分 以数串格式返回主机字符串 以数串格式返回范围标识字符串 以数串格式返回服务字符串 |
四类网络相关信息总结如下表:
信息 | 数据文件 | 结构 | 键值查找函数 |
主机 网络 协议 服务 |
/etc/hosts /etc/networks /etc/protocols /etc/services |
hostent netent protoent servent |
gethostbyaddr,gethostbyname getnetbyaddr,getnetbyname getprotobyname,getprotobynumber getservbyname,getservbyport |
UNIX网络编程读书笔记:名字与地址转换的更多相关文章
- UNIX网络编程--读书笔记
会集中这段时间写UNIX网络编程这本书的读书笔记,准备读三本,这一系类的文章会不断更新,一直会持续一个月多,每篇的前半部分是书中讲述的内容,每篇文章的后半部分是自己的心得体会,文章中的红色内容是很重要 ...
- UNIX网络编程读书笔记:简介
认知套接口编程接口 理解原始套接口(raw socket)的概念 值得注意的是,客户和服务器是典型的用户进程,而TCP和IP协议则通常是系统内核协议栈的一部分. 上图中在TCP和UDP之间留有间隙 ...
- UNIX网络编程读书笔记:地址操纵函数
地址格式转换函数:它们在ASCII字符串(人们比较喜欢用的格式)与网络字节序的二进制值(此值存于套接口地址结构中)间转换地址. 1.inet_aton.inet_addr.inet_ntoa inet ...
- UNIX网络编程读书笔记:原始套接口
概述 应用程序可以绕过传输层而直接使用IPv4和IPv6,这称为原始套接口(raw socket).http://www.cnblogs.com/nufangrensheng/p/3583435.ht ...
- UNIX网络编程读书笔记:套接口选项
概述 有很多方法来获取和设置影响套接口的选项: getsockopt和setsockopt函数 fcntl函数 ioctl函数 getsockopt和setsockopt函数 这两个函数仅用于套接口. ...
- Unix 网络编程 读书笔记1
第一章: C/C++语言提供两种不同的编程模式:IPL32和PL64.► IPL32 ● 表示integer/pointer/long三种数据类型是32位(4个字节),在这种模式下,提供32位的地址空 ...
- UNIX网络编程读书笔记:套接口地址结构
前言 大多数套接口函数都需要一个指向套接口地址结构的指针作为参数.每个协议族都定义它自己的套接口地址结构.这些结构的名字均以"sockaddr_"开头,并以对应每个协议族的唯一后缀 ...
- Unix 网络编程 读书笔记2
第三章 套接字编程简介 每一个 Socket 都用一个半相关描述:{协议,本地地址,本地端口}一个完整的 Socket 则用一个相关描述{协议,本地地址,本地端口,远程地址,远程端口}每一个 Sock ...
- UNIX网络编程读书笔记:UNIX域协议
概述 UNIX域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务器通信的一种方法,所用API与在不同主机上执行客户/服务器通信所用的API(套接口API)相同.UNIX域协议可视为进程间通信 ...
随机推荐
- 【BZOJ 4104】 4104: [Thu Summer Camp 2015]解密运算 (智商)
4104: [Thu Summer Camp 2015]解密运算 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 370 Solved: 237 De ...
- 【BZOJ 1880】 [Sdoi2009]Elaxia的路线 (最短路树)
1880: [Sdoi2009]Elaxia的路线 Description 最近,Elaxia和w**的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间. ...
- 51nod1218 最长递增子序列 V2
看见标签推荐顺便就做了吧 记$f[i], g[i]$为$i$的含$i$的前缀最长递增子序列和后缀递增子序列 只要满足$f[i] + g[i] == LIS + 1$,那么$i$就是可能的 对于$i$而 ...
- JZYZOJ1237 教授的测试 dfs
http://172.20.6.3/Problem_Show.asp?id=1237 锻炼搜索的代码能力,不错的题. 开始对dfs到底向下传递什么搞不清楚,需要想一下,noip难度的题还有这种情况 ...
- bzoj 3940: [Usaco2015 Feb]Censoring -- AC自动机
3940: [Usaco2015 Feb]Censoring Time Limit: 10 Sec Memory Limit: 128 MB Description Farmer John has ...
- poj 2828 buy Tickets 用线段树模拟带插入的队列
Buy Tickets Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=2 ...
- PAT甲级1016. Phone Bills
PAT甲级1016. Phone Bills 题意: 长途电话公司按以下规定向客户收取费用: 长途电话费用每分钟一定数量,具体取决于通话时间.当客户开始连接长途电话时,将记录时间,并且客户挂断电话时也 ...
- CentOS 6.9/7通过yum安装指定版本的Node.js
说明:通过yum好处其实很多,环境变量不用配置,配置文件放在大家都熟悉的地方,通过rpm -ql xxx可以知道全部文件的地方等等. Node.js(8.x) 一.安装和配置 1.安装Node.js ...
- CentOS 6.9设置阿里云源/163源
阿里云: 1.备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2.下载新的CentOS ...
- MAC 版本 phpstorm 配置 theme
mac 版本的配置文件在:./Library/Preferences/WebIde70/colors/ 将文件复制到这个目录中,然后phpStorm设置中,IDE设置->editor->f ...