簡體   English   中英

從GetAdaptersAddresses()獲取IP_ADDRESS_STRING?

[英]Get an IP_ADDRESS_STRING from GetAdaptersAddresses()?

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;

似乎建議人類可讀的IP地址字符串的唯一字段是Address,它是一個SOCKET_ADDRESS結構,定義如下:

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

反過來,它使用另一種結構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字符串)?

您可以使用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) );

IP_ADAPTER_UNICAST_ADDRESS包含SOCKET_ADDRESSAddress ,其中又包含LPSOCKADDR在lpSockAddr -你可以將此轉換為使用IPv4字符串形式WSAAddressToString

看一下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

我想你也可以在給定結構定義(下面復制)的情況下以類似的方式為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;
};

您只需將_SOCKET_ADDRESS.lpSockaddr_SOCKET_ADDRESS.iSockaddrLength作為lpsaAddressdwAddressLength參數傳遞給WSAAddressToString函數即可。 WSAAddressToString將為您進行必要的轉換,無需深入挖掘。

function SOCKET_ADDRESS_ToString(const Addr: SOCKET_ADDRESS): String;
var
  Len: DWORD;
begin
  if (Addr.lpSockaddr = nil) or (Addr.iSockaddrLength <= 0) then
  begin
    Result := '';
    Exit;
  end;
  Len := 0;
  WSAAddressToString(Addr.lpSockaddr, Addr.iSockaddrLength, nil, nil, Len);
  SetLength(Result, Len);
  if WSAAddressToString(Addr.lpSockaddr, Addr.iSockaddrLength, nil, PChar(Result), Len) = 0 then
    SetLength(Result, Len - 1)
  else
    Result := '';
end;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM