关于hostent以及in_addr结构体
  TEZNKK3IfmPf 2023年11月12日 24 0

在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

 

十六进制数展开后,是小端排列。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月12日 0

暂无评论

推荐阅读
  TEZNKK3IfmPf   2024年05月31日   52   0   0 linux服务器
  TEZNKK3IfmPf   2024年05月31日   31   0   0 linux服务器centos
TEZNKK3IfmPf