2019独角兽企业重金招聘Python工程师标准>>>

1 域名系统

域名系统(Domain Name System,DNS)主要用于主机名字与IP地址之间的映射。主机名既可以是一个简单名字(simple name),例如mimiasd,也可以是一个全限定域名(Fully Qualified Domain Name,FQDN),例如mimiasd.unpbook.com。

2 gethostbyname函数

查找主机名最基本的函数是gethostbyname。如果成功,它就返回一个指向hostent结构的指针,该结构中含有所查找主机的所有IPv4地址。这个函数只能处理IPv4的地址。gethostbyname2函数通过设置AF值,可查看IPv6的地址。

#inlcude <netdb.h>
/* Return entry from host data base for host with NAME.This function is a possible cancellation point and therefore notmarked with __THROW.  */
extern struct hostent *gethostbyname (const char *__name);#ifdef __USE_MISC
/* Return entry from host data base for host with NAME.  AF must beset to the address type which is `AF_INET' for IPv4 or `AF_INET6'for IPv6.This function is not part of POSIX and therefore no officialcancellation point.  But due to similarity with an POSIX interfaceor due to the implementation it is a cancellation point andtherefore not marked with __THROW.  */
extern struct hostent *gethostbyname2 (const char *__name, int __af);

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

/* Description of data base entry for a single host.  */
struct hostent
{char *h_name;            /* Official name of host.  */char **h_aliases;        /* Alias list.  */int h_addrtype;        /* Host address type.  */int h_length;            /* Length of address.  */char **h_addr_list;        /* List of addresses from name server.  */
#if defined __USE_MISC || defined __USE_GNU
# define    h_addr    h_addr_list[0] /* Address, for backward compatibility.*/
#endif
};

图1-1 hostent结构和它所包含的信息

gethostbyname与我们介绍的其他套接字函数的不同之处在于:当错误发生时,它不设置errno变量,而是将全局整数变量h_errno设置为在头文件<netdb.h>中定义的下列常值之一:

/* Possible values left in `h_errno'.  */
# define HOST_NOT_FOUND    1    /* Authoritative Answer Host not found.  */
# define TRY_AGAIN    2    /* Non-Authoritative Host not found,or SERVERFAIL.  */
# define NO_RECOVERY    3    /* Non recoverable errors, FORMERR, REFUSED,NOTIMP.  */
# define NO_DATA    4    /* Valid name, no data record of requestedtype.  */

例子:

#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>int main( int argc, char **argv )
{char *ptr, **pptr;char str[ INET_ADDRSTRLEN ];struct hostent *hptr;// 给每个命令行参数调用gethostnamewhile( --argc > 0 ){// 输出规范主机名ptr = *++argv;if( ( hptr = gethostbyname( ptr ) ) == NULL ){printf( " gethostbyname error for host: %s: %s ", ptr, hstrerror( h_errno ) );continue;}printf( " official hostname: %s\n ", hptr->h_name );// 输出别名列表for( pptr = hptr->h_aliases; *pptr != NULL; pptr++ )printf( " \talias: %s\n ", *pptr );// pptr指向一个指针数组,其中每个指针指向一个地址。对于每一个地址,我们调用inet_ntop并输出返回的字符串switch( hptr->h_addrtype ){case AF_INET:pptr = hptr->h_addr_list;for( ; *pptr != NULL; pptr++ )printf( " \taddress: %s\n ", inet_ntop( hptr->h_addrtype, *pptr, str, sizeof( str ) ) );break;default:printf( " unknown address type " );break;}}exit( 0 );
}

3 gethostbyaddr函数

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

#inlcude <netdb.h>
/* Return entry from host data base which address match ADDR withlength LEN and type TYPE.This function is a possible cancellation point and therefore notmarked with __THROW.  */
extern struct hostent *gethostbyaddr (const void *__addr, __socklen_t __len,int __type);

4 getservbyname函数和getservbyport函数

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

#inlcude <netdb.h>
/* Return entry from network data base for network with NAME andprotocol PROTO.This function is a possible cancellation point and therefore notmarked with __THROW.  */
extern struct servent *getservbyname (const char *__name, const char *__proto);

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

/* Description of data base entry for a single service.  */
struct servent
{char *s_name;            /* Official service name.  */char **s_aliases;        /* Alias list.  */int s_port;            /* Port number.  */char *s_proto;        /* Protocol to use.  */
};

本函数的典型调用如下:

struct servent *sptr;sptr = getservbyname( " domain ", " udp " ); // DNS using UDP
sptr = getservbyname( " ftp ", " tcp " ); // FTP using TCP
sptr = getservbyname( " ftp ", NULL ); // FTP using TCP
sptr = getservbyname( " ftp ", " udp " ); // this call will fail

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

#inlcude <netdb.h>
/* Return entry from service data base which matches port PORT andprotocol PROTO.This function is a possible cancellation point and therefore notmarked with __THROW.  */
extern struct servent *getservbyport (int __port, const char *__proto);

port函数的值必须为网络字节序。本函数的典型调用如下;

struct servent *sptr;sptr = getservbyport( hton( 53 ), " udp " ); // DNS using UDP
sptr = getservbyport( hton( 21 ), " tcp " ); // FTP using TCP
sptr = getservbyport( hton( 21 ), NULL ); // FTP using TCP
sptr = getservbyport( hton( 21 ), " udp " ); // this call will fail

必须清楚的是,有些端口号在TCP上用于一种服务,在UDP上却用于完全不同的另一种服务。

例子:使用gethostbyname和getservbyname

#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>#define MAX_MESG_SIZE 1024char *  sock_ntop(const struct sockaddr *sa, socklen_t salen);
char *  Sock_ntop(const struct sockaddr *sa, socklen_t salen);int main( int argc, char **argv )
{int sockfd, n;char recvline[ MAX_MESG_SIZE + 1 ];struct sockaddr_in servaddr;struct in_addr **pptr;struct in_addr *inetaddrp[ 2 ];struct in_addr inetaddr;struct hostent *hp;struct servent *sp;// 第一个命令行参数是主机名,我们把它作为参数传递给gethostbyname,第二个命令行参数是服务名,我们把它作为// 参数传递给getservbyname。假设我们的代码使用TCP,我们把它作为getservbyname的第二个参数。如果// gethostbyname名字查找失败,我们就尝试使用inet_aton函数,确定其参数是否已是ASCII格式的地址,若是则构造// 一个由相应的地址构成的单元素列表。if( argc != 3 ){printf( " usage:daytimecpcli1 <hostname> <service> \n" );exit( 1 );}if( ( hp = gethostbyname( argv[ 1 ] ) ) == NULL ){ if( inet_aton( argv[ 1 ], &inetaddr ) == 0 ){printf( " hostname error for %s: %s \n", argv[ 1 ], hstrerror( h_errno ) );exit( 1 );} else{inetaddrp[ 0 ] = &inetaddr;inetaddrp[ 1 ] = NULL;pptr = inetaddrp;}}else{pptr = ( struct in_addr ** ) hp->h_addr_list;}if( ( sp = getservbyname( argv[ 2 ], "tcp" ) ) == NULL ){printf( " getservbyname error for %s \n", argv[ 2 ] );exit( 1 );}// 我们把对socket和connect的调用放在一个循环中,该循环为服务器主机的每个地址执行一次,直到// connect成功或IP地址列表试完为止。调用socket以后,我们以服务器主机的IP地址和端口填装网际网套接字// 地址结构。尽管我们可以把对bzero的调用和它后面的两个赋值语句置于循环体之外以提高执行效率,不过下面代码要// 简介些。与服务器建立连接几乎不会称为网络客户的性能瓶颈。for( ; *pptr != NULL; pptr++ ){sockfd = socket( AF_INET, SOCK_STREAM, 0 );bzero( &servaddr, sizeof( servaddr ) );servaddr.sin_family = AF_INET;servaddr.sin_port = sp->s_port;memcpy( &servaddr.sin_addr, *pptr, sizeof( struct in_addr ) );printf( " trying %s\n ", Sock_ntop( ( struct sockaddr* ) &servaddr, sizeof( servaddr ) ) );//接着调用connect。如果调用成功,那就使用break语句终止循环,否则输出一个出错消息并关闭套接字。我们直到// connect调用失败的描述符必须关闭,不能再用。if( connect( sockfd, ( struct sockaddr* ) &servaddr, sizeof( servaddr ) ) == 0 )break; // successelse{printf( " connect error \n" );close( sockfd );}}if( *pptr == NULL ){printf( " unable to connect \n" );exit( 1 );}while( ( n = read( sockfd, recvline, MAX_MESG_SIZE ) ) > 0 ){recvline[ n ] = 0; // null terminatefputs( recvline,stdout );}exit( 0 );
}

5 getaddrinfo函数

gethostbyname和gethostbyaddr这两个函数仅仅支持IPv4。getadddrinfo函数能够处理名字到地址以及服务到端口这两种转换,返回的是一个sockaddr结构而不是一个地址列表。

#include <netdb.h>
/* Translate name of a service location and/or a service name to set ofsocket addresses.This function is a possible cancellation point and therefore notmarked with __THROW.  */
extern int getaddrinfo (const char *__restrict __name,const char *__restrict __service,const struct addrinfo *__restrict __req,struct addrinfo **__restrict __pai);

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

/* Structure to contain information about address of a service provider.  */
struct addrinfo
{int ai_flags;            /* Input flags.  */int ai_family;        /* Protocol family for socket.  */int ai_socktype;        /* Socket type.  */int ai_protocol;        /* Protocol for socket.  */socklen_t ai_addrlen;        /* Length of socket address.  */struct sockaddr *ai_addr;    /* Socket address for socket.  */char *ai_canonname;        /* Canonical name for service location.  */struct addrinfo *ai_next;    /* Pointer to next in list.  */
};

在addrinfo结构中返回的信息可现在用于socket调用,随后现成用于适合客户的connect或senfto调用,或者是适合服务器的bind调用。

图1-2 getaddrinfo返回信息的实例

端口53用于domain服务。这个端口在套接字地址结构中按照网络字节序存放。返回的ai_protocol值或为IPPROTO_TCP,或为IPPROTO_UDP。

图1-3 为每个IP地址返回的addrinfo结构的数目

6 gai_strerror函数

图1-4给出了可由getaddrinfo返回的非0错误值的名字和含义。gai_strerror以这些值为它的唯一参数,返回一个指向对应的出错信息串指针。

/* Convert error return from getaddrinfo() to a string.  */
extern const char *gai_strerror (int __ecode) __THROW;

图1-4 getaddrinfo返回的非0错误常值

7 freeaddrinfo函数

由getaddrinfo返回的所有存储空间都使动态获取的(譬如来自malloc调用),包括addrinfo结构、ai_addr结构和ai_cannonname字符串。这些诶储存空间通过调用freeaddrinfo返还给系统。

#include <netdb.h>
/* Free `addrinfo' structure AI including associated storage.  */
extern void freeaddrinfo (struct addrinfo *__ai) __THROW;

__ai参数指向由getaddrinfo返回的第一个adddinfo结构。这个链表中的所有结构以及由它们指向的任何动态存储空间都被释放掉。

转载于:https://my.oschina.net/u/2537915/blog/661144

网络编程学习——名字与地址转换(一)相关推荐

  1. 《UNIX网络编程:套接字联网API》啃书笔记(第8UDP套接字编程、11章地址转换)

    基本UDP套接字编程 下图为UDP客户/服务器程序的函数调用: 注意客户不与服务器建立连接,而是只管使用sendto函数给服务器发送数据报,其中必须指定目的地的地址作为参数.类似的,服务器不接受来自客 ...

  2. 【Socket网络编程】3.字节序转换函数htons、htonl ,地址转换函数inet_ntoa、inet_ntop、inet_pton、inet_addr

    字节序转换函数htons.htonl 地址转换函数inet_ntoa.inet_ntop.inet_pton.inet_addr 1.字节序转换函数 #include <arpa/inet.h& ...

  3. C++网络编程学习:服务端多线程分离业务处理高负载

    网络编程学习记录 使用的语言为C/C++ 源码支持的平台为:Windows / Linux 笔记一:建立基础TCP服务端/客户端  点我跳转 笔记二:网络数据报文的收发  点我跳转 笔记三:升级为se ...

  4. C++网络编程学习:网络数据报文的收发

    网络编程学习记录 使用的语言为C/C++ 源码支持的平台为:Windows 笔记一:建立基础TCP服务端/客户端  点我跳转 笔记二:网络数据报文的收发  点我跳转 笔记三:升级为select网络模型 ...

  5. 15Java网络编程学习笔记

    Java网络编程学习笔记 文章目录 1 网络基础 1.1 网络通信 1.2 网络 1.3 IP地址 1.5 域名 1.6 端口号 1.7 网络通信协议 1.8 TCP协议 1.9 UDP协议 2 In ...

  6. java 网络编程学习笔记

    java 网络编程学习笔记 C/S模式:客户端和服务器 客户端创建流程 1 1.建立Socket端点 2 3 Socket s = new Socket(绑定地址, 绑定端口); 2.确认源数据方式和 ...

  7. python网络编程学习笔记(二)

    python网络编程学习(四) 多用途客户端协议 一.ftp 功能:上传下载文件,删除命名文件,建立删除目录,自动压缩,保存目录 1.代码: #coding=utf-8 '''连接远程ftp服务器,显 ...

  8. [Linux网络编程学习笔记]索引

    一.Linux基本知识 [学习笔记]Linux平台的文件I/O操作 [学习笔记]Linux平台的文件,目录及操作 [Linux学习笔记]标准输入输出 [Linux学习笔记]进程概念及控制 [Linux ...

  9. 名字与地址转换getservbyname 与 getservbyport函数

    名字与地址转换getservbyname 与 getservbyport函数 服务也通常靠名字来标志,getservbyname函数用于根据给定名字查找相应服务. #include struct    ...

最新文章

  1. Python函数式编程-map/reduce
  2. 取文字_取一个好听的女孩名字
  3. linux内核启动后门,Linux下编写隐蔽的自启动回连后门
  4. SparkSql官方文档中文翻译(java版本)
  5. 在linux下也能进行51单片机开发吗?送你一份教程。
  6. java实现人脸识别源码【含测试效果图】——DaoImpl层(BaseDaoUtilImpl)
  7. OpenShift Origin中的Kubernetes Spark运算符(第1部分)
  8. julia在mac环境变量_在Julia中确定值/变量的类型
  9. 网页javascript部分
  10. matlab createtask,Matlab批量与createjob
  11. 现代化蔬菜大棚采用什么和计算机自动控制,温室大棚自动控制系统存在的意义以及未来的发展...
  12. 去找工作还要先交押金我认为不太靠谱
  13. 分享一篇获取键盘数值的js(限制在IE浏览器)
  14. Java-接口第一篇认识Interface
  15. 语音识别 | 数据堂方言语音数据集
  16. 说说 SpringMVC 工作原理
  17. 截止失真放大电路_数字电路基础(一)
  18. Mybatis 特殊符号(大于,小于,不等于)及常用函数总结
  19. Mac安装steam提示Steam needs to be online to update. Please confirm your network connection and try again
  20. 生产进度管理系统为制造管理提供较完善的解决方案

热门文章

  1. Winsock Fix for Windows 7
  2. 计算机专业中专自我鉴定范文,中专计算机专业毕业自我鉴定
  3. 【筛法求素数】HDU-1239 Calling Extraterrestrial Intelligence Again
  4. VMware安装Centos7系统
  5. [原] 手擀寿面祝妈妈生日快乐
  6. 在.NET中实现彩色光标/动画光标和自定义光标[转]
  7. java8 集合的交集、并集、差集
  8. JavaScript练习题# Day03 作业
  9. vue如何引入外部js文件,待解决,急!!!
  10. 无MAC法安装genymotion的解决办法_Invalid reply from server..