最近发现很多小伙伴在自学Linux网络编程这本书,中间可能会有许多不解的疑惑,书上有些地方讲解的也不是很透彻,恰巧之前选修过这门课,今天分享一个遇到的问题。
首先请看书的229页,8.4.4 函数gethostbyname不可重入的例子
先看下这段代码:
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
struct hostent *ht=NULL;
char host[]="www.sina.com.cn"; /*查询sina的主机域名*/
char host1[]="www.sohu.com"; /*查询sohu的主机域名*/
char str[30];
struct hostent *ht1=NULL, *ht2=NULL;
ht1 = gethostbyname(host); /*查询"www.sina.com.cn"*/
ht2 = gethostbyname(host1); /*查询"www.sohu.com"*/
int j = 0;
for(j = 0;j<2;j++){
if(j == 0)
ht = ht1; /*sina*/
else
ht =ht2; /*sohu*/
if(ht){
int i = 0;
printf("get the host:%s addr\n",host); /*原始域名*/
printf("name:%s\n",ht->h_name); /*名称*/
/*协议族AF_INET为IPv4或者AF_INET6为IPv6*/
printf("type:%s\n",ht->h_addrtype==AF_INET?"AF_INET":"AF_INET6");
printf("legnth:%d\n",ht->h_length); /*IP地址的长度*/
/*打印IP地址*/
for(i=0;;i++){
if(ht->h_addr_list[i] != NULL){ /*不是IP地址数组的结尾*/
printf("IP:%s\n",inet_ntop(ht->h_addrtype,ht->h_addr_list[i],str,30)); /*打印IP地址*/
} else{ /*达到结尾*/
break; /*退出for循环*/
}
}
/*打印域名地址*/
for(i=0;;i++){/*循环*/
if(ht->h_aliases[i] != NULL){ /*没有到达域名数组的结尾*/
printf("alias %d:%s\n",i,ht->h_aliases[i]); /*打印域名*/
} else{ /*结尾*/
break; /*退出循环*/
}
}
}
}
return 0;
}
这是这段代码的运行结果,其中第二行的运行结果是我的朋友问我最不能理解的:为什么ht的h_name输出结果是sohu而不是sina。
这就涉及到gethostbyname的函数处理方式,只需要了解一下几点:
第一:gethostbyname处理数据时返回的结果是存储在一个静态结构体变量中的,静态变量大家都懂,作为本地的一个全局变量,只初始化一次,也就是说,下次对这个变量进行操作时,是基于这次的结果来操作的
第二:ht1和ht2这个结构体指针在运行gethostbyname这个函数后指向的是同一个地址(即上面gethostbyname存储返回结果的变量地址)(大家可以在编译器里分部执行查看变量值的变化)
(表达可能不是很准确,大家可以理解我的意思即可或提出意见)
了解了这两点后,我们就可以知道,(14和15行)在第一次gethostbyname运行完之后,存储返回结果的变量的值存储的是原始域名host的域名(即www.sina.com.cn),此时ht1也指向这个存储这个变量的地址,但在第二次运行完之后,这个值已经变为了(www.sohu.com),而且此时ht1和ht2指向的地址都是这个结果的地址,所以第二行输出结果时即使此时ht赋值为ht1,(25和26行)结果仍是www.sohu.com,大家可以分享一下自己的看法或提出意见。