2010-10-21 15 views
5

GetAdaptersAddresses() sẽ giúp bạn có địa chỉ ở định dạng IP_ADAPTER_UNICAST_ADDRESS, được định nghĩa là:Nhận IP_ADDRESS_STRING từ GetAdaptersAddresses()?

typedef struct _IP_ADAPTER_UNICAST_ADDRESS { 
    union { 
    struct { 
     ULONG Length; 
     DWORD Flags; 
    } ; 
    } ; 
    struct _IP_ADAPTER_UNICAST_ADDRESS *Next; 
    SOCKET_ADDRESS      Address; 
    IP_PREFIX_ORIGIN     PrefixOrigin; 
    IP_SUFFIX_ORIGIN     SuffixOrigin; 
    IP_DAD_STATE      DadState; 
    ULONG        ValidLifetime; 
    ULONG        PreferredLifetime; 
    ULONG        LeaseLifetime; 
    UINT8        OnLinkPrefixLength; 
} IP_ADAPTER_UNICAST_ADDRESS, *PIP_ADAPTER_UNICAST_ADDRESS; 

Các lĩnh vực duy nhất mà dường như cho thấy chuỗi địa chỉ IP của con người có thể đọc được là địa chỉ, mà là một cấu trúc SOCKET_ADDRESS định nghĩa là:

typedef struct _SOCKET_ADDRESS { 
    LPSOCKADDR lpSockaddr; 
    INT  iSockaddrLength; 
} SOCKET_ADDRESS, *PSOCKET_ADDRESS; 

trong đó, lần lượt, sử dụng một cấu trúc, sockaddr, định nghĩa là:

Xin lỗi, đó là cách để phức tạp để trả lời ở đây, vì nó thay đổi tùy thuộc vào IPv4 vs IPv6 và W edition indows ... vì vậy đây là một liên kết đến định nghĩa:

http://msdn.microsoft.com/en-us/library/ms740496%28v=VS.85%29.aspx

Nếu bạn chưa nhận được chóng mặt nhưng như tôi đã làm và sau đó thông qua mê cung này các định nghĩa, bạn có thể nhận thấy rằng đó là một cơn ác mộng để truy xuất kiểu chuỗi chấm cũ tốt của địa chỉ IP, vì nó được sử dụng dễ dàng hơn nhiều khi sử dụng GetAdaptersInfo().

Câu hỏi của tôi là: Có thực sự chức năng Trình trợ giúp IP có thể chuyển đổi IP_ADAPTER_UNICAST_ADDRESS thành chuỗi chấm IPv4 (hoặc chuỗi IPv6) không?

Trả lời

6

Bạn có thể sử dụng GetIpAddrTable - số returned data structure chứa DWORD dwAddr là địa chỉ IPv4. Mã mẫu trên liên kết đầu tiên đó sẽ hiển thị cho bạn những gì bạn muốn. đoạn trích ngắn gọn để cho bạn thấy những gì tôi có nghĩa là:

if ((dwRetVal = GetIpAddrTable(pIPAddrTable, &dwSize, 0)) != NO_ERROR) { 
    printf("GetIpAddrTable failed with error %d\n", dwRetVal); 
    if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),  // Default language 
         (LPTSTR) & lpMsgBuf, 0, NULL)) { 
     printf("\tError: %s", lpMsgBuf); 
     LocalFree(lpMsgBuf); 
    } 
    exit(1); 
} 

printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); 
for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { 
    printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); 
    IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; 
    printf("\tIP Address[%d]:  \t%s\n", i, inet_ntoa(IPAddr)); 

Các IP_ADAPTER_UNICAST_ADDRESS chứa một SOCKET_ADDRESS trong Address, mà lần lượt chứa một LPSOCKADDR trong lpSockAddr - bạn có thể chuyển đổi này để dưới dạng chuỗi ipv4 sử dụng WSAAddressToString.

+0

@Steve, cảm ơn nhưng đây không thực sự là những gì tôi đang tìm kiếm. GetAdaptersAddresses() cung cấp nhiều thông tin hơn nữa - cho cả IPv4 và IPv6 - và tôi muốn tuân thủ theo đề xuất của Microsoft.Tất cả những gì tôi đang thiếu là một chức năng tiện lợi "phiên dịch", có thể lấy IP_ADAPTER_UNICAST_ADDRESS làm tham số và xuất ra một chuỗi. Thay vì tái phát minh ra bánh xe và tự viết nó, có lẽ bạn biết về chức năng hiện tại như vậy? Trong chính API hoặc ở nơi khác, có lẽ một số mẫu? –

+2

@Android Eve - xem chỉnh sửa, bạn có thể sử dụng 'WSAAddressToString' cho việc này. –

+0

Một lần nữa, bạn thể hiện kiến ​​thức ấn tượng về không gian IP Helper của PSDK. Nhờ câu trả lời của bạn, tôi đã có thể phát hiện một vài chức năng liên quan hơn, đặc biệt là RtlIpv4AddressToString() và RtlIpv6AddressToString() mà, không may tồn tại trong WDK, không phải là PSDK. Tôi sẽ đánh dấu câu trả lời của bạn ngay khi được chấp nhận. Trừ khi một câu trả lời mới hơn cho thấy một chức năng làm tương tự cho * cả * IPv6 và IPv4. –

3

Hãy xem tài liệu cho SOCKADDR. Điều đó dẫn chúng ta đến tài liệu cho SOCKADDR_STORAGE, là cấu trúc trợ giúp cho cả IPv4 và IPv6.

Trích dẫn từ tài liệu sockaddr:

chức năng Winsock sử dụng sockaddr không giải thích đúng là con trỏ đến một cấu trúc sockaddr. Cấu trúc được hiểu là khác nhau trong ngữ cảnh của các gia đình địa chỉ khác nhau.

Đối với ipv4, bạn có thể truyền con trỏ sockaddr tới con trỏ sockaddr_in và sau đó truy cập thông tin địa chỉ IPv4 từ đó. Sau đó, bạn có thể sử dụng trình tạo chuỗi yêu thích của mình để tạo chuỗi có dấu chấm tứ.

sockaddr_in* address = (sockaddr_in*) temp->Address.lpSockaddr; 
uint32_t ipv4 = address->sin_addr.S_un.S_addr; 
// First octet: address->sin_addr.S_un.S_un_b.s_b1 
// Second octet: address->sin_addr.S_un.S_un_b.s_b2 
// Third octet: address->sin_addr.S_un.S_un_b.s_b3 
// Fourth octet: address->sin_addr.S_un.S_un_b.s_b4 

Tôi sẽ tưởng tượng rằng bạn cũng có thể truyền địa chỉ cho ipv6 theo cách tương tự với định nghĩa struct (được sao chép bên dưới).

struct sockaddr { 
     ushort sa_family; 
     char sa_data[14]; 
}; 

struct sockaddr_in { 
     short sin_family; 
     u_short sin_port; 
     struct in_addr sin_addr; 
     char sin_zero[8]; 
}; 

struct sockaddr_in6 { 
     short sin6_family; 
     u_short sin6_port; 
     u_long sin6_flowinfo; 
     struct in6_addr sin6_addr; 
     u_long sin6_scope_id; 
};