apue和unp的学习之旅11——名字与数值地址转换

//-------------------------------------1.为什么使用名字好-----------------------------------------

我们应该使用名字而不是数值来标识主机(例如数值206.6.226.33),服务器(例如端口13代表标准的daytime服务器),然而出于以下几个理由,我们应该使用名字而不是数值:

1).名字好记住

2).数值地址可以变动而名字保持不变

3).随着往IPv6上转移,数值地址变得相当长,手工键入地址很容易出错。

//-----------------------------------------2.域名系统---------------------------------------------

域名系统(Domain Name System,DNS)主要用于主机名字与IP地址之间的映射。

主机名:可以是一个简单名字,例如solaris或bsdi,也可以是一个全限定域名(Fully Qualified Domain Name,FQDN),例如solaris.unpbook.com。

DNS中的条目称为资源记录(resource record,RR)

A记录: A记录把一个主机名映射成一个32位的IPv4地址。

举例来说,以下是unpbook.com域中关于主机solaris的4个DNS记录,其中第一个是一个A记录:

AAAA记录:称为“四A”记录的AAAA记录把一个主机名映射成一个128位的IPv6地址。

PTR记录:称为指针记录的PTR记录把IP地址映射成主机名。

MX记录:MX(mail exchanger)记录把一个主机指定作为给定主机的“邮件交换器”,上例中主机有2个MX记录,优先级分别是5,10,当存在多个MX记录时,它们按照优先级顺序使用,值越小优先级越高。

//-------------------------------------3.解析器和名字服务器---------------------------------------

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

诸如在本书编写的客户和服务器程序通过调用称为解析器(resolver)的函数库中的函数接触DNS服务器。常见的解析器函数有gethostbyname和gethostbyaddr。

下图展示了应用进程,解析器和名字服务器之间的一个典型的关系。

解析器代码通过读取其系统相关配置文件确定本组织机构的名字服务器们的所在位置(上图只展示了一个服务器,大多数组织机构运行多个名字服务器,处于可靠和冗余的目的,必须要设置多个名字服务器)文件/etc/resolv.conf通常包含本地名字服务器主机的IP地址。

解析器使用UDP向本地名字服务器发出查询,如果本地名字服务器不知道答案,它通常就会使用UDP在整个因特网上查询其他名字服务器,如果答案太长,超出了UDP消息的承载能力,本地名字服务器和解析器会自动切换到TCP。

//-------------------------------------4.gethostbyname函数---------------------------------------------

struct hostent

{

char*  h_name;

char** h_aliases;

int    h_addrtype;

int    h_length;

int**  h_addr_list;

};

#include <netdb.h>

struct hostent* gethostbyname(const char* hostname);

// ret:若成功则为非空指针,若出错则为NULL且设置h_errno

如果调用成功就返回一个指向hostent结构的指针,该结构中含有所查找主机的所有ipv4地址,这个函数的局限是只能返回IPv4地址。按照DNS的说法,gethostname执行的是对A记录的查询,它只能返回IPv4地址。即使该主机有IPv6地址,返回的也仅仅是IPv4地址。

//-------------------------------------5.gethostbyaddr函数----------------------------------------

#include <netdb.h>

struct hostent* gethostbyaddr(const char* addr, socklen_t len, int family);

// ret:若成功则为非空指针,若出错则为NULL且设置h_errno

addr参数实际实际上不是char*类型,而是一个指向存放IPv4地址的某个in_addr结构的指针;len参数是这个结构的大小:对于IPv4地址为4,family参数为AF_INET;

按照DNS的说法,gethostbyaddr在in_addr.arpa域中向一个名字服务器查询PTR记录。

//--------------------------------6.getservbyname函数和getservbyport--------------------------------

如果程序通过名字而不是端口号来指代一个服务,而且从名字到端口号的映射关系保存在一个文件中(/etc/services),那么即使端口号发生变动,我么你需要改动的仅仅是/etc/services文件中的某一行,而不必重新编译应用程序。getservbyname函数用于根据给定名字查找相应服务。

#include <netdb.h>

struct servent* getservbyname(const char* servname, const char* protoname);

// ret:若成功则为非空指针,若出错则为NULL

struct servent

{

char*  s_name;

char** s_aliases;

int    s_port;

char*  s_proto;

};

注意,既然端口号已经是以网路字节序返回的,把它存放到套接字地址结构时绝对不能再调用htons。

#include  <netdb.h>

struct servent* getservbyport(int port, const char* protoname);

注意,port必须是网络字节序。

//-----------------------------------------7.getaddrinfo函数----------------------------------------

#include <netdb.h>

int  getaddrinfo(const char* hostname, const char* service, const struct addrinfo* hints, struct addrinfo** result);

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

本函数通过result指针参数返回一个指向addrinfo结构链表的指针,而addrinfo结构定义在头文件<netdb.h>中。

struct addrinfo

{

int ai_flags;

int ai_famlily;

int ai_socktype;

int ai_protocol;

socklen_t ai_addrlen;

char* ai_canonname;

struct sockaddr* ai_addr;

struct sockaddr* ai_next;

};

其中hostname参数是一个主机名或地址串(IPv4的点分十进制串或IPv6的十六进制数串),service参数是一个服务名或十进制端口号数串。

hints参数可以是一个空指针,也可以是一个指向某个addr_info结构的指针,调用者在这个结构中填入关于期望返回的信息类型的暗示。

//------------------------------------8.gai_strerror函数-----------------------------------------

#include <netdb.h>

const char* gai_strerror(int error);

// ret:指向错误描述信息字符串的指针

//-------------------------------------9.getnameinfo函数-----------------------------------------

#include <netdb.h>

int getnameinfo(const struct sockaddr* sockaddr, socklen_t addrlen, char* host, socklen_t hostlen,

char* serv, socklen_t servlen, int flag);

// ret:若成功则为0,若出错则非0

sockaddr指向一个套接字地址结构,其中包含待转换成直观可读的字符串的协议地址,该结构及其长度通常由accept,recvfrom,getsockname或getpeername返回。

待返回的2个直观可读字符串由调用者预先分配存储空间,host和hostlen指定主机字符串,serv和servlen指定服务字符串。如果调用者不想返回主机字符串,那就指定hostlen为0,同样,把servlen指定0就是不想返回服务字符串。

sock_ntop和getnameinfo的差别在于,前者不涉及DNS,只返回IP地址和端口号的一个可显示版本,后者通过尝试获取主机和服务的名字。

apue和unp的学习之旅11——名字与数值地址转换,布布扣,bubuko.com

时间: 2024-12-19 07:28:04

apue和unp的学习之旅11——名字与数值地址转换的相关文章

apue和unp的学习之旅09——套接字选项

//-----------------------------------1.getsockopt和setsockopt-------------------------------------- #include <sys/socket.h> int getsockopt(int sockfd, int level, int optname, void* optval, socklen_t* optlen); int setsockopt(int sockfd, int level, int

apue和unp的学习之旅10——基本udp套接字编程

使用UDP编写的一些常见的应用程序有:DNS(域名系统),NFS(网络文件系统),SNMP(简单网络管理协议). //---------------------------------1.recvfrom函数和sendto函数---------------------------------- #include <sys/socket.h> ssize_t  recvfrom(int sockfd, void* buff, size_t nbytes, int flags, struct so

apue和unp的学习之旅07——多种边界条件的讨论

了解一些边界条件,通过观察这些情形,弄清在网络层次发生什么以及它们怎样反映到套接字api,这将很多其它地理解这些层次的工作原理,体会怎样编写应用程序来处理这些情形. //--------------------------------1.刚连接立即断开---------------------------------- 当三TCP路握手完毕从而连接建立之后.客户TCP却发送了RST,在server端看来,就在该连接已由TCP排队,等着server进程调用accept的时候RST到达. 怎样处理这

iOS学习之旅10 ATS(App Transport Security)对HTTPS协议要求引起的问题

问题描述 编写以下代码获取网络某个资源的MIMEType 1 -(void)getMIMEType 2 { 3 //路径 4 NSURL *url = [NSURL URLWithString:@"https://www.baidu.com/img/bd_logo1.png"]; 5 //请求对象 6 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 7 NSOperationQueue *

Hasen的linux设备驱动开发学习之旅--异步通知

/** * Author:hasen * 参考 :<linux设备驱动开发详解> * 简介:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:异步通知 * Date:2014-11-05 */ 一.异步通知的概念和作用 阻塞和非阻塞访问.poll()函数提供了较好地解决设备访问的机制,但是如果有了异步通知整套机制就更 加完整了. 异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这 一点非常类似于硬件上"中断"的概

【Linux学习之旅】之Ubuntu14.04安装及美化之后要做的事

以上是我的Ubuntu里安装的一些软件. 1)卸载不需要的软件,在启动器里右键单击要卸载的软件即可. 2)升级你的软件版本 sudo apt-get update && sudo apt-get upgrade 3)安装Fcitx sudo apt-get install fcitx fcitx-googlepinyin 4) 安装samba samba服务器安装后,就可以与你所在的网络中的其他用户共享文件了. sudo apt-get install samba 5)安装媒体工具 sud

Matlab 学习之旅(一)

一.脚本文件和M函数 1.1  脚本文件      脚本文件是命令行的集合,由一系列 MATLAB 命令.内置函数及M 文件等组成的文件.脚本文件在MATLAB 编译器中建立,并被保存为.m文件,按顺序执行,执行过程中生成的变量存放在当前工作空间中.     注意:脚本不能返回输出变量,所有创建的变量将保留在工作空间中,但脚本能提供图形输出,就像使用图形输出函数plot()一样. 例子:    利用M文件编辑器,键入命令并保存为magicrank.m        array = zeros(1

我的大学【我的计算机学习之旅&amp;我的计算机考研之旅】

freemarker定义一个连续的序列 1.简易说明 定义一个连续的序列,并打印出序列中的元素 2.实现源码 <#--freemarker定义了一个连续的序列--> <#assign nums=1..100/> <#list nums as num> ${num} </#list> 3.实现结果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 3

180分钟的python学习之旅

最近在很多地方都可以看到Python的身影,尤其在人工智能等科学领域,其丰富的科学计算等方面类库无比强大.很多身边的哥们也提到Python非常的简洁方便,比如用Django搭建一个见得网站只需要半天时间即可,因此也吸引了我不小的兴趣.之前相亲认识过一个姑娘是做绿色环保建筑设计行业的,提过她们的建筑物的建模也是使用Python,虽然被女神给拒绝了,但学习还是势在必行的,加油. 这部分只涉及python比较基础的知识,如复杂的面向对象.多线程.通信等知识会放在之后的深入学习中介绍,因此整个学习过程也