Linux中gethostbyname()函数和getaddrinfo()函数的简介和使用


前言

在写项目代码的过程中要将域名解析成IP地址,查阅了资料,对gethostbyname()函数和getaddrinfo()函数有所了解,所以进行一个总结,以便查阅。


一、gethostbyname()函数

1.gethostbyname()函数原型:

struct hostent *gethostbyname(const char *hostname);

该函数需要包含#include <netdb.h>头文件,参数hostname 为主机名,也就是域名;使用该函数时,传递域名字符串,返回一个hostent 的结构体指针;如果返回的结构体指针为空,则表示有错误发生;hostent的定义如下:

struct hostent
{
    char *h_name;  //官方域名
    char **h_aliases;  //域名别名
    int  h_addrtype;  //IP地址的类型,IPv4或者IPv6,IPv4 对应 AF_INET,IPv6 对应 AF_INET6
    int  h_length;  //IP地址长度
    char **h_addr_list;  //IP地址列表,同一个域名可能对应多个IP地址
}

2.简单例子

#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    if (argc < 2)
    {
        printf("param < 2");
        return -1;
    }

    char *domain_name = argv[1];
    struct hostent *hptr;

    hptr = gethostbyname(domain_name);
    if (hptr == NULL)
    {
        printf("gethostbyname error for host: %s: %s\n", domain_name, hstrerror(h_errno));
        return -1;
    }

    // 输出主机的官方域名
    printf("\tofficial: %s\n", hptr->h_name);

    // 输出主机的别名
    char **pptr;
    char str[INET_ADDRSTRLEN];        //INET_ADDRSTRLEN 表示16字节长度
    for (pptr=hptr->h_aliases; *pptr!=NULL; pptr++)
    {
        printf("\ttalias: %s\n", *pptr);
    }

    // 输出ip地址
    for (pptr = hptr->h_addr_list; *pptr!=NULL; pptr++)
    {
        // inet_ntop将网络传输的数值格式转化为点分十进制的ip地址格式
        printf("\taddress: %s\n",inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)));
    }

    return 0;
}

3.运行结果
在这里插入图片描述

二、getaddrinfo()函数

1.getaddrinfo()函数原型

int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result );

参数说明:
hostname:主机名或域名
service:服务名可以是十进制的端口号,也可以是已定义的服务名称,如ftp、http等
hints:可以是一个空指针,也可以是一个指向某个addrinfo结构体的指针,调用者在这个结构中填入关于期望返回的信息类型的暗示。举例来说:指定的服务既可支持TCP也可支持UDP,所以调用者可以把hints结构中的ai_socktype成员设置成SOCK_DGRAM使得返回的仅仅是适用于数据报套接口的信息。
result:将结果存进一个指向addrinfo结构体链表的指针中。
返回值:0—成功,非0—出错

2.额外知识了解:struct addrinfo的定义如下:

struct addrinfo
{
  int ai_flags;                 
  int ai_family;                // 地址族,可取的值有AF_INET(IPv4) AF_INET6(IPv6) AF_UPSPEC(可以代表任何域)
  int ai_socktype;              // socket的类型,主要有SOCK_STREA(流)M和SOCK_DGRAM(数据报)两种
  int ai_protocol;              // socket协议 IPPROTO_IPV4、IPPROTO_IPV6等
  socklen_t ai_addrlen;         // socket地址长度
  struct sockaddr *ai_addr;     // socket地址信息
  char *ai_canonname;           
  struct addrinfo *ai_next;     // 指向下一个socket地址信息的指针
};

在这里简单说明下struct sockaddr和struct sockaddr_in的区别,下面的例子中会用到;
struct sockaddr的 定义如下:

struct sockaddr 
{  
    unsigned short    sa_family;      // 2 字节地址族, AF_xxx  
    char              sa_data[14];    // 14 字节的协议地址  
};

struct sockaddr_in的定义如下:

struct sockaddr_in 
{  
    short            sin_family;      // 2 字节地址族, AF_xxx
    unsigned short   sin_port;        // 2 字节端口号,htons(3490)  
    struct in_addr   sin_addr;        // 4 字节IP地址  
    char             sin_zero[8];     // 8 字节填充位  
};  

可以发现这两个结构体一样大,都是16个字节,而且都有family属性,不同的是:sockaddr用其余14个字节来表示地址相关信息,而sockaddr_in把14个字节拆分成sin_port, sin_addr和sin_zero分别表示端口、ip地址,sin_zero用来填充字节使sockaddr_in和sockaddr保持一样大小。所以在使用中sockaddr是给操作系统用的,而sockaddr_in给编码者使用;
一般的用法为:
程序员把类型、ip地址、端口填充sockaddr_in结构体,然后强制转换成sockaddr,作为参数传递给系统调用函数。

2.简单例子

#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    struct addrinfo hints;
    struct addrinfo *result;
    struct addrinfo *curr;
    int ret = -1;
    char ipstr[INET_ADDRSTRLEN];
    struct sockaddr_in  *ipv4;
    
    // 设置期望值
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_INET;    
    hints.ai_socktype = SOCK_STREAM;
    
    ret = getaddrinfo(argv[1], NULL, &hints, &result);
    if (ret != 0) 
    {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
        exit(EXIT_FAILURE);                                     
    }   
    
    // 输出获得IP地址
    for (curr = result; curr != NULL; curr = curr->ai_next)
    {   
        ipv4 = (struct sockaddr_in *)curr->ai_addr; 
        // inet_ntop将网络传输的数值格式转化为点分十进制的ip地址格式
        inet_ntop(curr->ai_family, &ipv4->sin_addr, ipstr, INET_ADDRSTRLEN);
        printf("ipaddr:%s\n", ipstr);
    }
    
    /* No longer needed */ 
    freeaddrinfo(result);
    return 0;
}

3.运行结果
在这里插入图片描述

总结

以上就是今天总结的内容,据了解gethostbyname()函数属于半淘汰状态,目前主要使用getaddrinfo()函数。如以上内容有问题,欢迎大家在评论区指正。
参考链接:
http://c.biancheng.net/view/2357.html.
https://blog.csdn.net/u011003120/article/details/78277133.
https://blog.csdn.net/xdshengk/article/details/47313103.

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值