2011-05-10 50 views
16

我想了解getaddrinfo函数返回的内容:的getaddrinfo和IPv6

#include <stdlib.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <sys/socket.h> 
#include <netdb.h> 

int main (int argc, char *argv[]) 
{ 


struct addrinfo *res = 0 ; 

    getaddrinfo("localhost", NULL ,NULL,&res); 
    printf("ai_flags -> %i\n", res->ai_flags) ; 
    printf("ai_family -> %i\n", res->ai_family) ; 
    printf("ai_socktype -> %i\n", res->ai_socktype) ; 
    printf("ai_protocol -> %i\n", res->ai_protocol) ; 
    printf("ai_addrlen -> %i\n", res->ai_addrlen) ; 
    struct sockaddr_in* saddr = (struct sockaddr_in*)res->ai_addr; 
    printf("ai_addr hostname -> %s\n", inet_ntoa(saddr->sin_addr)); 

    freeaddrinfo(res); 

    return 0 ; 
} 

结果:

ai_flags -> 40 
ai_family -> 2 
ai_socktype -> 1 
ai_protocol -> 6 
ai_addrlen -> 16 
ai_addr hostname -> 127.0.0.1 

在/ etc/hosts中,我已经有了:

127.0.0.1 localhost  
::1  localhost 

Getaddrinfo只返回127.0.0.1而不是:: 1?我不明白为什么?

第二个问题是我在哪里可以找到这些整数(40,2,1,6等)的含义?我读过这个人,但没有任何关于这个的。

我也想知道是否有可能提供IPv6地址(例如:: 1),并且函数返回名称:localhost?

非常感谢!

+6

根据手册页,getaddrinfo分配空间并填充从&res开始的链接列表。我认为它会返回多个条目,并且需要通过res-> ainext – roirodriguez 2011-05-10 21:21:06

回答

9

@jwodder和@onteria_覆盖IPv6的部分很好,所以我就解决数字部分:

ai_flags -> 40 

也许这将是以下两者之和在/usr/include/netdb.h

# define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */ 
# define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose 

这是协议族,INET,INET6,APX,Unix等:

ai_family -> 2 

bits/socket.h:78:#define PF_INET  2 /* IP protocol family. */ 
bits/socket.h:119:#define AF_INET  PF_INET 

这是插座型,流,DGRAM,分组,RDM,SEQPACKET:

ai_socktype -> 1 

bits/socket.h:42: SOCK_STREAM = 1,  /* Sequenced, reliable, connection-based 

上位协议,TCP,UDP,TCP6,UDP6,UDPlite ,OSPF,ICMP等:

ai_protocol -> 6 

滑稽的是,在/etc/protocols

tcp 6 TCP  # transmission control protocol 

大小struct sockaddr。 (不同而有所差异基础上的地址族唉!)

ai_addrlen -> 16 

这是因为你要回来struct sockaddr_in,看到linux/in.h

#define __SOCK_SIZE__ 16  /* sizeof(struct sockaddr) */ 
struct sockaddr_in { 
    sa_family_t  sin_family; /* Address family  */ 
    __be16  sin_port; /* Port number   */ 
    struct in_addr sin_addr; /* Internet address  */ 

    /* Pad to size of `struct sockaddr'. */ 
    unsigned char  __pad[__SOCK_SIZE__ - sizeof(short int) - 
      sizeof(unsigned short int) - sizeof(struct in_addr)]; 
}; 

,最后一个,从/etc/hosts :)

ai_addr hostname -> 127.0.0.1 
9

res还包含一个字段struct addrinfo *ai_next;,它是指向getaddrinfo找到的其他条目的指针,如果没有其他条目,则为NULL。如果您检查res->ai_next,则应该找到IPv6条目。

至于struct addrinfo中的整数字段,它们对应于具有实现定义值的预定义常量,并且整数值本身并不具有普遍意义。如果你想知道一个给定的字段表示,比较其对可分配给该字段的常量(SOCK_STREAMSOCK_DGRAM等,为ai_socktype; IPPROTO_TCPIPPROTO_UDP等,为ai_protocol;等等),或者对于ai_flags ,测试对应于预定义常数的每个比特(例如,if (res->ai_flags & AI_NUMERICHOST) {printf("ai_flags has AI_NUMERICHOST\n"); })。

6
extern struct sockaddr_in6 create_socket6(int port, const char * address) { 

    struct addrinfo hints, *res, *resalloc; 
    struct sockaddr_in6 input_socket6; 
    int errcode; 

    /* 0 out our structs to be on the safe side */ 
    memset (&hints, 0, sizeof (hints)); 
    memset (&input_socket6, 0, sizeof(struct sockaddr_in6)); 

    /* We only care about IPV6 results */ 
    hints.ai_family = AF_INET6; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_DEFAULT; 

    errcode = getaddrinfo (address, NULL, &hints, &res); 
    if (errcode != 0) 
    { 
    perror ("[ERROR] getaddrinfo "); 
    return input_socket6; 
    } 

    resalloc = res; 

    while (res) 
    { 
     /* Check to make sure we have a valid AF_INET6 address */ 
     if(res->ai_family == AF_INET6) { 
       /* Use memcpy since we're going to free the res variable later */ 
         memcpy (&input_socket6, res->ai_addr, res->ai_addrlen); 

         /* Here we convert the port to network byte order */ 
         input_socket6.sin6_port = htons (port); 
         input_socket6.sin6_family = AF_INET6; 
       break; 
     } 

     res = res->ai_next; 
    } 

    freeaddrinfo(resalloc); 

    return input_socket6; 
} 

下面是一些解释它的代码。基本上除非你给getaddrinfo一些提示,告诉它只能使用IPV6,否则它也会给出IPV4结果。这就是为什么你必须循环显示结果。

+0

来遍历链表。我修复了内存泄漏。 – selbie 2011-07-16 00:52:10

4

对大多数零件都给出了其他答案,但要回答这个最后部分:

我也想知道是否可以给一个IPv6地址(例如:: 1),并且该函数返回名称:localhost?

你想要的功能是getnameinfo();给定一个套接字地址,它返回一个字符串名称