关于hostent以及in_addr结构体

来源:互联网 发布:期货交易程序化软件 编辑:程序博客网 时间:2024/06/06 06:59

在linux网络编程中,gethostbyname函数可以通过域名url直接获得ip地址相关信息,返回的是一个名为hostent的结构体,通过man gethostbyname手册查询后,发现该结构体如下

         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 */           }           #define h_addr h_addr_list[0] /* for backward compatibility */


该结构体的成员前四个都比较容易理解,h_name是服务器端的名称,比如打开www.baiducom,那么相应的h_name便是www.a.shifen.com,h_aliases是服务器为了负载均衡所使用的域名,h_addrtype指出ip地址的版本号,ipv4以及ipv6, 对理解造成障碍的是h_addr_list,这是一个字符指针的指针,但惟独只有首个成员有意义,就是h_addr_list[0], 通过宏定义将h_addr命名为h_addr_list[0], 其实这个指针指向的,是一个名为in_addr的结构体的地址,可以通过强制类型转换(struct in_addr *) h->h_addr 得到该结构体。而struct in_addr结构体定义 如下

 struct in_addr {               in_addr_t s_addr;           };

只有 一个成员变量,ni_addr_t其实是int类型,通过宏定义命名为ni_addr_t,在不同硬件平台上估计有 不同的长度,而s_addr,其实是将点分十进制构成的ip地址转换成十进制数字后的值。


下面通过一个小程序验证一下

#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <netdb.h>#include <sys/types.h>#include <netinet/in.h>int main (int argc, char *argv[]){struct hostent *h;/* 检测命令行中的参数是否存在 */if (argc != 2) {   /* 如果没有参数,给出使用方法 */  printf ("usage: getip address\n");  /* 然后退出 */  exit(1);}/* 取得主机信息 */if ((h=gethostbyname(argv[1])) == NULL){/* 如果gethostbyname失败,则给出错误信息 */herror("gethostbyname");/* 然后退出 */exit(1);}/* 列印程序取得的信息 */printf("h_name: %s\n", h->h_name);printf("h_aliases: %s\n", h->h_aliases[0]);printf("h_addrtype: %d\n", h->h_addrtype);printf("h_length: %d\n", h->h_length);struct in_addr *inaddr;inaddr = (struct in_addr *)h->h_addr;printf("IP Address: %x\n",inaddr->s_addr);/* 返回 */return 0;
编译#gcc  tes.c   -o tes.bin

执行# ./tes.bin  www.baidu.com

结果:

h_name: www.a.shifen.com
h_aliases: www.baidu.com
h_addrtype: 2
h_length: 4
IP Address: 69a9873d

上边的ip地址并非点分十进制的字符串的形式,而是已经按照字节排列的16进制形式。

这里会有一个非常令人困惑的地方,牵扯到字符以及整数在linux中的存储问题,linux系统中存储的规则是小段存储,就是说,一段数字或字符,权值小的,存储在地址的低端部分,权值高的,存储在地址高的部分,所有的数据和字符按照地址增长的方向存储。

比如, 69 a9 87 3d在地址中,如果由低向高排列的话,会是

3d, 87, a9, 69

明白这点了吗?通过一个小程序 来验证以下,将上边的代码添加如下函数

void show(int x){int a, b, c, d;a = x&0xff000000;a>>=24;b = x&0x00ff0000;b>>=16;c = x&0x0000ff00;c>>=8;d = x&0x000000ff;printf("%x %x %x %x\n", a, b, c, d);}
这个函数的功能是将整形变量x的按照字节长度展开


添加后是 这样:


#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <netdb.h>#include <sys/types.h>#include <netinet/in.h>\void show(int x);int main (int argc, char *argv[]){struct hostent *h;/* 检测命令行中的参数是否存在 */if (argc != 2) {   /* 如果没有参数,给出使用方法 */  printf ("usage: getip address\n");  /* 然后退出 */  exit(1);}/* 取得主机信息 */if ((h=gethostbyname(argv[1])) == NULL){/* 如果gethostbyname失败,则给出错误信息 */herror("gethostbyname");/* 然后退出 */exit(1);}/* 列印程序取得的信息 */printf("h_name: %s\n", h->h_name);printf("h_aliases: %s\n", h->h_aliases[0]);printf("h_addrtype: %d\n", h->h_addrtype);printf("h_length: %d\n", h->h_length);struct in_addr *inaddr;inaddr = (struct in_addr *)h->h_addr;printf("IP Address: %x\n",inaddr->s_addr);show(inaddr->s_addr);/* 返回 */return 0;}void show(int x){int a, b, c, d;a = x&0xff000000;a>>=24;b = x&0x00ff0000;b>>=16;c = x&0x0000ff00;c>>=8;d = x&0x000000ff;printf("%x %x %x %x\n", a, b, c, d);}


执行结果如下:


h_name: www.a.shifen.com
h_aliases: www.baidu.com
h_addrtype: 2
h_length: 4
IP Address: 7da9873d
7d a9 87 3d
十六进制数展开后,是小端排列。




0 0
原创粉丝点击