getaddrinfo, getnameinfo(替代gethostbyname, gethostbyaddr), gethostname

时间:2022-04-27 02:20:22

http://beej.us/guide/bgnet/output/html/multipage/gethostbynameman.html

http://baike.baidu.com/link?url=3qVTFgQmU8MMzq33GlJwPwQkJr8lKZDVLAKNOQfA_GEytnp5EPc3E9gnTwyaL0WqT5oJDqTjf9rY1JoTMrLUvq


gethostbyname, gethostbyaddr是不可重入函数;已经被getaddrinfo, getnameinfo替代。



http://beej.us/guide/bgnet/output/html/multipage/getaddrinfoman.html

http://baike.baidu.com/view/6757218.htm

The  getaddrinfo(3)  function  combines  the functionality provided by the getipnodebyname(3), getipnodebyaddr(3), getservbyname(3), and getservbyport(3)
       functions into a single interface.  The thread-safe getaddrinfo(3) function creates one or more socket address structures that can be used by the bind(2)
       and connect(2) system calls to create a client or a server socket.  线程安全,融合了多个函数的功能。

       int getaddrinfo(const char *node, const char *service,
                       const struct addrinfo *hints,
                       struct addrinfo **res);

       struct addrinfo {
           int     ai_flags; -- 按位赋值
           int     ai_family;
           int     ai_socktype;
           int     ai_protocol;
           size_t  ai_addrlen;
           struct sockaddr *ai_addr;
           char   *ai_canonname;
           struct addrinfo *ai_next;
       };

  • node或service参数最多可能有一个为NULL。
  • node 要么为点分式地址(dotted-decimal format for IPv4, hexadecimalformat for IPv6) 要么为主机名。
  • 如果hints中ai_flags设置了AI_NUMERICHOST,则node必须为数字地址;  
  • service为端口号或者端口名。如果不为空,为端口名,则必须可以解析,通过/etc/services。
  • 如果ai_flags设置了AI_CANONNAME,则char   *ai_canonname存储了第一个地址,相当于快捷方式?
  • 如果node为null,但没有设置AI_PASSIVE,则返回回环地址,用于本地服务;
  • 如果node为null,但设置AI_PASSIVE,则返回所有地址,相当于bind(INADDR_ANY)。
  • 根据node和service查找到对应的addr info。如果此信息被connect调用,则表示这是被监听对象;而监听者可以通过node里面设置。node如果是fe80这种IP V6地址,必须接%eth来指定接口,则监听者就是这个local IP;如果是raw socket,则监听端口就是hints里面的 ai_protocol。  getaddrinfo() supports the address%scope-id notation for specifying the IPv6 scope-ID.


// code for a server waiting for connections
// namely a stream socket on port 3490, on this host's IP
// either IPv4 or IPv6.

int sockfd;  
struct addrinfo hints, *servinfo, *p;
int rv;

memset(&hints, 0, sizeof hints);--- 必须先清零再使用
hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP address ------- 此情况下,第一个参数可以为null,则返回所有IP,相当于bind(INADDR_ANY)。


if ((rv = getaddrinfo(NULL, "3490", &hints, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
    exit(1);
}

// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) { ---------------------------------使用实例:可以参考gsoap的tcp_connect,soap_bind等函数。
    if ((sockfd = socket(p->ai_family, p->ai_socktype,
            p->ai_protocol)) == -1) {
        perror("socket");
        continue;
    }

    if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { ------ 尽管返回多个ip,但有些可能会失败,所以需要尝试
        close(sockfd);
        perror("bind");
        continue;
    }

    break; // if we get here, we must have connected successfully
}

if (p == NULL) {
    // looped off the end of the list with no successful bind
    fprintf(stderr, "failed to bind socket\n");
    exit(2);
}

freeaddrinfo(servinfo); // all done with this structure ------- 必须调用,否则内存泄露


getaddrinfo() supports the address%scope-id notation for specifying the IPv6 scope-ID. ----------- 如ipv6%eth0,即指定接口。