2014-01-30 60 views
0

我有以下兩套代碼:getaddrinfo似乎在Windows和Ubuntu之間返回不同的結果?

的Windows

#undef UNICODE 

#include <winsock2.h> 
#include <ws2tcpip.h> 
#include <stdio.h> 

// link with Ws2_32.lib 
#pragma comment (lib, "Ws2_32.lib") 

int __cdecl main(int argc, char **argv) 
{ 

    //----------------------------------------- 
    // Declare and initialize variables 
    WSADATA wsaData; 
    int iResult; 
    INT iRetval; 

    DWORD dwRetval; 
    argv[1] = "www.google.com"; 
    argv[2] = "80"; 
    int i = 1; 

    struct addrinfo *result = NULL; 
    struct addrinfo *ptr = NULL; 
    struct addrinfo hints; 

    struct sockaddr_in *sockaddr_ipv4; 
// struct sockaddr_in6 *sockaddr_ipv6; 
    LPSOCKADDR sockaddr_ip; 

    char ipstringbuffer[46]; 
    DWORD ipbufferlength = 46; 

    /* 
    // Validate the parameters 
    if (argc != 3) { 
     printf("usage: %s <hostname> <servicename>\n", argv[0]); 
     printf("getaddrinfo provides protocol-independent translation\n"); 
     printf(" from an ANSI host name to an IP address\n"); 
     printf("%s example usage\n", argv[0]); 
     printf(" %s www.contoso.com 0\n", argv[0]); 
     return 1; 
    } 
    */ 

    // Initialize Winsock 
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 
    if (iResult != 0) { 
     printf("WSAStartup failed: %d\n", iResult); 
     return 1; 
    } 

    //-------------------------------- 
    // Setup the hints address info structure 
    // which is passed to the getaddrinfo() function 
    ZeroMemory(&hints, sizeof(hints)); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
    // hints.ai_protocol = IPPROTO_TCP; 

    printf("Calling getaddrinfo with following parameters:\n"); 
    printf("\tnodename = %s\n", argv[1]); 
    printf("\tservname (or port) = %s\n\n", argv[2]); 

//-------------------------------- 
// Call getaddrinfo(). If the call succeeds, 
// the result variable will hold a linked list 
// of addrinfo structures containing response 
// information 
    dwRetval = getaddrinfo(argv[1], argv[2], &hints, &result); 
    if (dwRetval != 0) { 
     printf("getaddrinfo failed with error: %d\n", dwRetval); 
     WSACleanup(); 
     return 1; 
    } 

    printf("getaddrinfo returned success\n"); 

    // Retrieve each address and print out the hex bytes 
    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) { 

     printf("getaddrinfo response %d\n", i++); 
     printf("\tFlags: 0x%x\n", ptr->ai_flags); 
     printf("\tFamily: "); 
     switch (ptr->ai_family) { 
      case AF_UNSPEC: 
       printf("Unspecified\n"); 
       break; 
      case AF_INET: 
       printf("AF_INET (IPv4)\n"); 
       sockaddr_ipv4 = (struct sockaddr_in *) ptr->ai_addr; 
       printf("\tIPv4 address %s\n", 
        inet_ntoa(sockaddr_ipv4->sin_addr)); 
       break; 
      case AF_INET6: 
       printf("AF_INET6 (IPv6)\n"); 
       // the InetNtop function is available on Windows Vista and later 
       // sockaddr_ipv6 = (struct sockaddr_in6 *) ptr->ai_addr; 
       // printf("\tIPv6 address %s\n", 
       // InetNtop(AF_INET6, &sockaddr_ipv6->sin6_addr, ipstringbuffer, 46)); 

       // We use WSAAddressToString since it is supported on Windows XP and later 
       sockaddr_ip = (LPSOCKADDR) ptr->ai_addr; 
       // The buffer length is changed by each call to WSAAddresstoString 
       // So we need to set it for each iteration through the loop for safety 
       ipbufferlength = 46; 
       iRetval = WSAAddressToString(sockaddr_ip, (DWORD) ptr->ai_addrlen, NULL, 
        ipstringbuffer, &ipbufferlength); 
       if (iRetval) 
        printf("WSAAddressToString failed with %u\n", WSAGetLastError()); 
       else  
        printf("\tIPv6 address %s\n", ipstringbuffer); 
       break; 
      case AF_NETBIOS: 
       printf("AF_NETBIOS (NetBIOS)\n"); 
       break; 
      default: 
       printf("Other %ld\n", ptr->ai_family); 
       break; 
     } 
     printf("\tSocket type: "); 
     switch (ptr->ai_socktype) { 
      case 0: 
       printf("Unspecified\n"); 
       break; 
      case SOCK_STREAM: 
       printf("SOCK_STREAM (stream)\n"); 
       break; 
      case SOCK_DGRAM: 
       printf("SOCK_DGRAM (datagram) \n"); 
       break; 
      case SOCK_RAW: 
       printf("SOCK_RAW (raw) \n"); 
       break; 
      case SOCK_RDM: 
       printf("SOCK_RDM (reliable message datagram)\n"); 
       break; 
      case SOCK_SEQPACKET: 
       printf("SOCK_SEQPACKET (pseudo-stream packet)\n"); 
       break; 
      default: 
       printf("Other %ld\n", ptr->ai_socktype); 
       break; 
     } 
     printf("\tProtocol: "); 
     switch (ptr->ai_protocol) { 
      case 0: 
       printf("Unspecified\n"); 
       break; 
      case IPPROTO_TCP: 
       printf("IPPROTO_TCP (TCP)\n"); 
       break; 
      case IPPROTO_UDP: 
       printf("IPPROTO_UDP (UDP) \n"); 
       break; 
      default: 
       printf("Other %ld\n", ptr->ai_protocol); 
       break; 
     } 
     printf("\tLength of this sockaddr: %d\n", ptr->ai_addrlen); 
     printf("\tCanonical name: %s\n", ptr->ai_canonname); 
    } 

    freeaddrinfo(result); 
    WSACleanup(); 

    return 0; 
} 

Ubuntu的

/* 
** listener.c -- a datagram sockets "server" demo 
*/ 

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 

#define MYPORT "4950" // the port users will be connecting to 

#define MAXBUFLEN 100 

// get sockaddr, IPv4 or IPv6: 
void *get_in_addr(struct sockaddr *sa) 
{ 
    if (sa->sa_family == AF_INET) { 
     return &(((struct sockaddr_in*)sa)->sin_addr); 
    } 

    return &(((struct sockaddr_in6*)sa)->sin6_addr); 
} 

int main(void) 
{ 
    int sockfd; 
    struct addrinfo hints, *servinfo, *p; 
    int rv; 
    int numbytes; 
    struct sockaddr_storage their_addr; 
    char buf[MAXBUFLEN]; 
    socklen_t addr_len; 
    char s[INET6_ADDRSTRLEN]; 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4 
    hints.ai_socktype = SOCK_DGRAM; 
    hints.ai_flags = AI_PASSIVE; // use my IP 

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

    // loop through all the results and bind to the first we can 
    for(p = servinfo; p != NULL; p = p->ai_next) { 
     if ((sockfd = socket(p->ai_family, p->ai_socktype, 
       p->ai_protocol)) == -1) { 
      perror("listener: socket"); 
      continue; 
     } 

     if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { 
      close(sockfd); 
      perror("listener: bind"); 
      continue; 
     } 

     break; 
    } 

    if (p == NULL) { 
     fprintf(stderr, "listener: failed to bind socket\n"); 
     return 2; 
    } 

    freeaddrinfo(servinfo); 

    printf("listener: waiting to recvfrom...\n"); 

    addr_len = sizeof their_addr; 
    if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0, 
     (struct sockaddr *)&their_addr, &addr_len)) == -1) { 
     perror("recvfrom"); 
     exit(1); 
    } 

    printf("listener: got packet from %s\n", 
     inet_ntop(their_addr.ss_family, 
      get_in_addr((struct sockaddr *)&their_addr), 
      s, sizeof s)); 
    printf("listener: packet is %d bytes long\n", numbytes); 
    buf[numbytes] = '\0'; 
    printf("listener: packet contains \"%s\"\n", buf); 

    close(sockfd); 

    return 0; 
} 

當我嘗試www.google.com,我沒有得到在Windows上返回的ipv6套接字 - 爲什麼是這樣?

輸出:(Ubuntu的)

[email protected]:~/Documents/dev/cs438/mp0/MP0$ ./a.out www.google.com 
IP addresses for www.google.com: 

IPv4: 74.125.228.115 
IPv4: 74.125.228.116 
IPv4: 74.125.228.112 
IPv4: 74.125.228.113 
IPv4: 74.125.228.114 
IPv6: 2607:f8b0:4004:803::1010 

輸出:(WIN)

Calling getaddrinfo with following parameters: 
     nodename = www.google.com 
     servname (or port) = 80 

getaddrinfo returned success 
getaddrinfo response 1 
     Flags: 0x0 
     Family: AF_INET (IPv4) 
     IPv4 address 74.125.228.114 
     Socket type: SOCK_STREAM (stream) 
     Protocol: Unspecified 
     Length of this sockaddr: 16 
     Canonical name: (null) 
getaddrinfo response 2 
     Flags: 0x0 
     Family: AF_INET (IPv4) 
     IPv4 address 74.125.228.115 
     Socket type: SOCK_STREAM (stream) 
     Protocol: Unspecified 
     Length of this sockaddr: 16 
     Canonical name: (null) 
getaddrinfo response 3 
     Flags: 0x0 
     Family: AF_INET (IPv4) 
     IPv4 address 74.125.228.116 
     Socket type: SOCK_STREAM (stream) 
     Protocol: Unspecified 
     Length of this sockaddr: 16 
     Canonical name: (null) 
getaddrinfo response 4 
     Flags: 0x0 
     Family: AF_INET (IPv4) 
     IPv4 address 74.125.228.112 
     Socket type: SOCK_STREAM (stream) 
     Protocol: Unspecified 
     Length of this sockaddr: 16 
     Canonical name: (null) 
getaddrinfo response 5 
     Flags: 0x0 
     Family: AF_INET (IPv4) 
     IPv4 address 74.125.228.113 
     Socket type: SOCK_STREAM (stream) 
     Protocol: Unspecified 
     Length of this sockaddr: 16 
     Canonical name: (null) 

回答

0

getaddrinfo實際上返回它從名稱服務器獲取結構。這種行爲取決於操作系統。

-1

getaddrinfo()在Windows上可以得到的IPv6地址。您所需要做的就是將hints.ai_flags設置爲AI_ALL。它可以同時獲得IPV4 & IPV6地址。但是,如果一個域名是ipv6,只能像ipv6.google.com一樣,該方法仍然無法獲得IPV6地址。

相關問題