从GetAdaptersAddresses()获取IP_ADDRESS_STRING?

And*_*Eve 7 c windows networking winapi

GetAdaptersAddresses()将以IP_ADAPTER_UNICAST_ADDRESS格式获取地址,其格式定义为:

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;
Run Code Online (Sandbox Code Playgroud)

似乎建议人类可读的IP地址字符串的唯一字段是Address,它是一个SOCKET_ADDRESS结构,定义如下:

typedef struct _SOCKET_ADDRESS {
  LPSOCKADDR lpSockaddr;
  INT        iSockaddrLength;
} SOCKET_ADDRESS, *PSOCKET_ADDRESS;
Run Code Online (Sandbox Code Playgroud)

反过来,它使用另一种结构SOCKADDR,定义为:

对不起,这是复杂的方式发布在这里,因为它取决于IPv4与IPv6和Windows版本...所以这里是定义的链接:

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

如果你还没有像我那样头晕目眩并遵循这个定义的迷宫,你可能会注意到检索IP地址的旧的虚线字符串样式是一个噩梦,因为使用GetAdaptersInfo()过去更容易.

我的问题是:是否有真正的 IP Helper功能可以将IP_ADAPTER_UNICAST_ADDRESS转换为IPv4点分支(或IPv6字符串)?

Ste*_*end 6

您可以使用GetIpAddrTable - 返回的数据结构包含一个DWORD dwAddr,即IPv4地址.第一个链接上的示例代码应该显示您想要的内容.摘要向您展示我的意思:

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) );
Run Code Online (Sandbox Code Playgroud)

IP_ADAPTER_UNICAST_ADDRESS包含SOCKET_ADDRESSAddress,其中又包含LPSOCKADDR在lpSockAddr -你可以将此转换为使用IPv4字符串形式WSAAddressToString.

  • @Android Eve - 看看编辑,你可以使用`WSAAddressToString`. (3认同)
  • @Android Eve - 请参阅文档 - "虽然`inet_ntoa`函数仅适用于IPv4地址,但`WSAAddressToString`函数适用于本地计算机上包含IPv6地址的Winsock提供程序支持的任何套接字地址." (2认同)

Wil*_*ord 5

查看SOCKADDR的文档。这引导我们查看SOCKADDR_STORAGE的文档,它是 IPv4 和 IPv6 的辅助结构。

引用 sockaddr 文档:

使用 sockaddr 的 Winsock 函数并不严格解释为指向 sockaddr 结构的指针。在不同地址族的上下文中,该结构有不同的解释。

对于 ipv4,您可以将 sockaddr 指针转换为 sockaddr_in 指针,然后从那里访问 IPv4 地址信息。然后,您可以使用您最喜欢的字符串生成器来生成点分四元格式的字符串。

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
Run Code Online (Sandbox Code Playgroud)

我想您也可以根据结构定义(复制如下)以类似的方式转换 ipv6 的地址。

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;
};
Run Code Online (Sandbox Code Playgroud)