[UNP]:名称-地址转换函数

下面将介绍名称(主机名,服务名)与地址之间的转换函数

1. gethostbyname()

该函数用于从主机名获取IP地址

  • struct hostent

    1
    2
    3
    4
    5
    6
    7
    struct hostent{
    char *h_name; /* 主机的官方名称 */
    char **h_aliases; /* 主机别名的指针数组 */
    int h_addrtype; /* 主机IP地址的类型 */
    int h_length; /* IPv4的地址长度 */
    char** h_addr_list; /* IPV4地址列表, 以NULL结尾, 注意这里存储的部分点分十进制串,而是网络字节序 */
    }
  • 图例

    1

  • gethostbyname

    1
    2
    3
    #include <netdb.h>
    struct hostent * gethostbyname(const char * hostname)
    // 成功:非空指针, 失败: NULL, h_errno被置为相关错误码
    • hostname

      主机名,如baidu.com

h_errno
gethostbyname()的特殊之处在于,当发生错误时,它不设置errno,而是将全局整数变量设置为定义在<netdb.h>中的以下常量之一

  • HOST_NOT_FOUND
  • TRY_RECOVER
  • NO_RECOVERY
  • NO_DATA

2. gethostbyaddr()

该函数将一个二进制IP地址转换为主机名

  • gethostbyaddr

    1
    2
    3
    4
    #include <netdb.h>

    struct hostent *gethostbyaddr(const void *addr, socklen_t len, int family);
    // return: 成功返回非空指针,失败返回NULL, 设置h_errno
    • addr

      二进制IP地址,通常传入的就是in_addr类型

    • len

      addr大小

    • family

      协议族

3. getservbyname(), getservbyport()

这两个函数用于获取相关服务(ftp, domain等)的信息

  • struct strvent

    1
    2
    3
    4
    5
    6
    7
    struct servent
    {
    char * s_name; // 官方服务名称
    char ** s_aliases; // 别名列表
    int s_port; // 端口号(网络字节序)
    char * s_proto; // 协议
    }
  • getservbyname

    一般使用该函数来获取某个服务的端口号

    1
    2
    3
    #include <netdb.h>
    struct servent * getservbyname(const char * servname, const char * protoname);
    // return: 成功返回非空指针,失败返回NULL
    • servname

      服务的名称,可以是domain, ftp

    • protoname

      协议名,可以是udp, tcp

      有的服务支持多种协议

  • getservbyport

    一般使用该函数来获取服务名称

    1
    2
    3
    #include <netdb.h>
    struct servent *getservbyport(int port, const char *protoname);
    // return: 成功返回非空指针,失败返回NULL
    • port

      服务所在的端口号, 必须得是网络字节序

      通常的使用方法如下

      1
      sptr = getservbyport(htons(21), "udp");
    • protoname

      协议名

4. getaddrinfo()

该函数能够处理名称到地址以及服务到端口这两种转换

  • getaddrinfo

    1
    2
    3
    4
    #include <netdb.h>
    int getaddrinfo(const char * hostname, const char * service,
    const struct addrinfo *hints,struct addrinfo **result);
    //return: 成功返回0, 失败返回非0错误值
    • hostname

      主机名

    • service

      服务名, 可以是字符串,也可以是网络字节序的端口号

    • hints

      • addrinfo

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        struct addrinfo{
        int ai_flags; // 选项
        int ai_family; // 地址族
        int ai_socktype; // 套接字类型
        int ai_protocol; // 协议类型
        socklen_t ai_addrlen; // ai_addr链表的大小
        char * ai_canonname; // 主机名
        struct sockaddr * ai_addr; // ptr to socket address structure
        struct addrinfo * ai_next; // ptr to next structure in linked list
        }

      该参数用于对函数的返回值进行过滤,如在ai_socktype字段填入SOCK_DGRAM, 那么函数就只会返回数据报套接字的信息

      hints参数中只能对以下字段进行设置

      可以设置的成员
      ai_flags 零个或多个在一起的AI_XXX值.
      ai_family 某个AF_XXX
      ai_socktype 某个SOCK_XXX值
      ai_protocol 某个写控制协议

      ai_flags可以设置的值如下

      ai_flags可能值 含义
      AI_PASSIVE 套接字将用于被动打开。
      AI_CANONNAME 告知 getaddrinfo 函数返回主机的规范名字
      AI_NUMERICHOST 防止任何类型的名字到地址映射, hostname参数必须为一个地址串
      AI_NUMERICSERV 防止任何类型的名字到服务的映射,service 参数必须是一个十进制端口号数串
      AI_V4MAPPED 如果同时指定 ai_family 成员的值为 AF_INET6,那么如果没有可用的AAAA记录,就返回与A记录对应的IPV4映射的IPV6地址
      AI_ALL 如果同时指定 AI_V4MAPPED 标志,那么除了返回与AAAA记录对应的IPV6地址外,还返回与A记录对应的IPV4映射的IPV6地址
      AI_ADDRCONFIG 按照所在主机的配置选择返回地址类型,也就是只查找与所在主机回馈接口以外的网络接口配置的IP地址版本一致的地址
      • AI_CANONNAME

        如果在hints中设置了该标志,那么返回的result链表的第一个节点的ai_canonname字段将包含所查找主机的规范名

    • result

      该参数返回最终的查询结果,是一个链表的首地址, 看起来像这样

      2

    该函数虽然功能很强大,但是有点过于复杂,UNP中也认为其并不好用,故在此不做过多描述

5. gai_strerror()

该函数用于解析getaddrinfo()返回的非零错误值,将errno转换为字符串

  • gai_strerror

    1
    2
    3
    #include <netdb.h>
    const char * gai_strerror(int error);
    // return:指向错误描述消息字符串的指针
    • error

      错误号

    具体的错误消息如下

    常数 说明
    EAI_AGAIN 名字解析中临时失败
    EAI_BADFLAGS ai_flags的值无效
    EAI_FAIL 名字解析中不可恢复地失败
    EAI_FAMILY 不支持 ai_family
    EAI_MEMORY 内存分配失败
    EAI_NONAME hostname或service未提供,或者不可知
    EAI_OVERFLOW 用户参数缓冲区溢出(仅限 getnameinfo 函数)
    EAI_SERVICE 不支持 ai_socktype 类型的service
    EAI_SOCKTYPE 不支持 ai_socktype
    EAI_SYSTEM 在errno变量中有系统错误返回

6. freeaddrinfo()

该函数同样与getaddrinfo()搭配使用, getaddrinfo()中返回的链表结构全部都是动态分配的(malloc), 需要调用freeaddrinfo()来将这些动态分配的结构释放

  • freeaddrinfo

    1
    2
    #include <netdb.h>
    void freeaddrinfo(struct addrinfo *ai)
    • ai

      该参数应该指向由getaddrinfo()返回的第一个addrinfo结构


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!