• getaddrinfo()函数详解


    Socket的地址查询函数

    http://blog.sina.com.cn/s/blog_988c054b010139e3.html

    http://www.cnblogs.com/cxz2009/archive/2010/11/19/1881693.html

    包含头文件
    #include<netdb.h>

    函数原型
    int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result );

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

    addrinfo结构体原型

    typedef struct addrinfo {
        int ai_flags;        //AI_PASSIVE,AI_CANONNAME,AI_NUMERICHOST
        int ai_family;        //AF_INET,AF_INET6
        int ai_socktype;    //SOCK_STREAM,SOCK_DGRAM
        int ai_protocol;    //IPPROTO_IP, IPPROTO_IPV4, IPPROTO_IPV6 etc.
        size_t ai_addrlen;            //must be zero or a null pointer
        char* ai_canonname;            //must be zero or a null pointer
        struct sockaddr* ai_addr;    //must be zero or a null pointer
        struct addrinfo* ai_next;    //must be zero or a null pointer
    }

    其中ai_flags、ai_family、ai_socktype说明如下:
    参数            取值            值            说明
    ai_family        AF_INET            2            IPv4
                    AF_INET6        23            IPv6
                    AF_UNSPEC        0            协议无关
    ai_protocol        IPPROTO_IP        0            IP协议
                    IPPROTO_IPV4    4            IPv4
                    IPPROTO_IPV6    41            IPv6
                    IPPROTO_UDP        17            UDP
                    IPPROTO_TCP        6            TCP
    ai_socktype        SOCK_STREAM        1            流
                    SOCK_DGRAM        2            数据报
    ai_flags        AI_PASSIVE        1            被动的,用于bind,通常用于server socket
                    AI_CANONNAME    2
                    AI_NUMERICHOST    4            地址为数字串

    对于ai_flags值的说明:
    AI_NUMERICHOST | AI_CANONNAME | AI_PASSIVE
    如上表所示,ai_flags的值范围为0~7,取决于程序如何设置3个标志位,比如设置ai_flags为 “AI_PASSIVE|AI_CANONNAME”,ai_flags值就为3。三个参数的含义分别为:
    (1)AI_PASSIVE 当此标志置位时,表示调用者将在bind()函数调用中使用返回的地址结构。当此标志不置位时,表示将在connect()函数调用中使用。当节点名位 NULL,且此标志置位,则返回的地址将是通配地址。如果节点名NULL,且此标志不置位,则返回的地址将是回环地址。
    (2)AI_CANNONAME当此标志置位时,在函数所返回的第一个addrinfo结构中的ai_cannoname成员中,应该包含一个以空字符结尾的字符串,字符串的内容是节点名的正规名。
    (3)AI_NUMERICHOST当此标志置位时,此标志表示调用中的节点名必须是一个数字地址字符串。

    addrinfo结构中的ai_flags有以下几种值:

    • AI_ADDRCONFIG: 查询配置的地址类型(IPv4或IPv6).
    • AI_ALL: 查找IPv4和IPv6地址(仅用于AI_V4MAPPED).
    • AI_CANONNAME: 需要一个规范名(而不是别名).
    • AI_NUMERICHOST: 以数字格式返回主机地址.
    • AI_NUMERICSERV: 以端口号返回服务.
    • AI_PASSIVE: socket地址用于监听绑定.
    • AI_V4MAPPED: 如果没有找到IPv6地址, 则返回映射到IPv6格式的IPv6地址.

    如果getaddrinfo失败, 不能使用perror或strerror来生成错误信息, 应该使用gai_strerror将返回的错误码转换成错误信息:

    • 原型: const char *gai_strerror(int error);
    • 头文件: <netdb.h>

    int connect_2_server(char* host, int port, int verb, PLAYER_INTERRUPT_CBK interrupt_cbk)
    {
        int  ret = 0;
        int  ai_port = 0;
        int  ai_family = 0;
    #ifdef LINUX_OS
        char ai_host[INET6_ADDRSTRLEN] = {0};
    #endif
        char portname[6];
        struct addrinfo *houts = NULL;
        struct addrinfo *ph = NULL;
        struct sockaddr_in* sinp = NULL;
        struct addrinfo hints;

        hints.ai_flags = 0;
        hints.ai_family = 0;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
        hints.ai_addrlen = 0;
        hints.ai_addr = NULL;
        hints.ai_canonname = NULL;
        hints.ai_next = NULL;
        sprintf(portname,"%d",port);
        if(getaddrinfo(host, portname, &hints, &houts)){
            printf("tcp: %s error, getaddrinfo return null ",__FUNCTION__);
            return GX_TCP_ERROR_FATAL;
        }   
        ph = houts;

    retry_host:
        if(ph == NULL){
            printf("cannot find hostname ");
            freeaddrinfo(houts);
            return GX_TCP_ERROR_FATAL;
        }   
        sinp = (struct sockaddr_in*)ph->ai_addr;
        ai_family = ph->ai_family;
        ai_port = ntohs(sinp->sin_port);
        if(ai_port != port){
            printf("ai_port:%d port:%d ",ai_port,port);
            ph = ph->ai_next;
            goto retry_host;
        }
    #ifdef LINUX_OS
        if(inet_ntop(ph->ai_family,&sinp->sin_addr, ai_host, INET6_ADDRSTRLEN) == NULL){
            ph = ph->ai_next;
            printf("get addr %s ",strerror(errno));
            goto retry_host;
        }
    #endif

        //printf("family is %s ", (ai_family==AF_INET)?"AF_INET":"AF_INET6");
        //printf("host is %s ", ai_host);
        //printf("port is %d ", ai_port);
        ret = connect2server_with_af(ai_family,(struct sockaddr*)sinp, verb, interrupt_cbk);
        if(ret < 0){
            ph = ph->ai_next;
            goto retry_host;
        }

        freeaddrinfo(houts);
        return ret;
    }


  • 相关阅读:
    安装virtualbox后无法上网
    win8 添加语言现象 (中英文切换路径)
    pre-condition & post-condition
    win8系统 host process for windows tasks has stopped working
    Chrome一直提醒要翻译网页
    百度首页导航设置
    停止windows8自动下载更新系统
    win8 添加开机启动项 (类似win7系统中开始->选择要启动的程序)
    扩展欧几里得定理
    UVA1583-Digit Generator(紫书例题3.5)
  • 原文地址:https://www.cnblogs.com/jingzhishen/p/3505190.html
Copyright © 2020-2023  润新知