系列文章目录
前言
在实际项目中,使用到Tcp连接服务器端,考虑到服务器端有可能提供的是IP地址,也有可能提供的是域名,所以就研究了一下如何从域名中获取真实的IP地址。
一、gethostbyname
主要使用到了gethostbyname这个函数,先带大家了解一下:
1、头文件和函数原型
#include <netdb.h>
struct hostent *gethostbyname(const char *hostname);
2、作用
用于返回对应于给定主机名的主机信息。
3、返回值
返回值 struct 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. */
#ifdef __USE_MISC
# define h_addr h_addr_list[0] /* Address, for backward compatibility.*/
#endif
};
从结构体中可以看到,不止返回IP地址,还返回了一下其他信息,具体含有如下:
h_name:该变量存有官方域名,官方域名代表某一主页,但实际上,一些著名公司的域名并未使用官方域名注册。
h_aliases:可以通过多个域名访问同一主页,同一IP可以绑定多个域名,因此,除官方域名外还可指定其他域名。
h_addrtype:gethostbyname函数不仅支持IPv4,还支持IPv6。因此可以通过此变量获取保存在h_addr_list的IP地址的地址族信息。若是IPv4,则此变量存有AF_INET。
h_length:保存IP地址长度。若是IPv4地址,因为是4个字节,则保存4;若是IPv6,因为是16个字节,故保存16。
h_addr_list:该变量以整数形式保存域名的IP地址。另外,用于访问量较大的网站可能分配多个IP给同一域名,利用多个服务器进行负载均衡,同样可以通过此变量获取IP地址信息。
h_addr:该变量是返回h_addr_list列表中的第一个数据。
二、封装函数获取IP
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
/**
* @brief 判断传入的是域名还是ip地址,如果是域名,就通过域名获取ip地址,如果是ip地址不处理,直接返回
* @param host : 域名或IP地址
* @return std::string 获取成功返回IP地址,失败返回空
*/
static std::string _GetServerIP(char *host)
{
if (host == NULL)
{
return std::string();
}
struct hostent *pstHostent = NULL;
if (inet_addr(host) == INADDR_NONE)
{
if ((pstHostent = gethostbyname(host)) == NULL)
{
return std::string();
}
char *ipaddr = inet_ntoa(*(struct in_addr *)pstHostent->h_addr);
if (ipaddr)
{
return std::string(ipaddr);
}
}
else
{
return std::string(host);
}
return std::string();
}
三、实例
#include <arpa/inet.h>
#include <vector>
int main(int argc, char *argv[])
{
char host[64] = {0};
snprintf(host, sizeof(host), "%s", "www.baidu.com");
std::string ipaddr = _GetServerIP(host);
printf("ipaddr:%s\n", ipaddr.c_str());
return 0;
}
运行结果:ipaddr:110.242.68.3
四、总结
封装的函数可以直接拿过来使用,已经验证了。