windows 从 GetAdaptersAddresses() 获取 IP_ADDRESS_STRING?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3989446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get an IP_ADDRESS_STRING from GetAdaptersAddresses()?
提问by Android Eve
GetAdaptersAddresses()will get you addresses in IP_ADAPTER_UNICAST_ADDRESS format, which is defined as:
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;
The only field that seems to suggest the human-readable IP address string is Address, which is a SOCKET_ADDRESS structure defined as:
似乎表明人类可读 IP 地址字符串的唯一字段是地址,它是一个 SOCKET_ADDRESS 结构,定义为:
typedef struct _SOCKET_ADDRESS {
LPSOCKADDR lpSockaddr;
INT iSockaddrLength;
} SOCKET_ADDRESS, *PSOCKET_ADDRESS;
Which, in turn, uses another structure, SOCKADDR, defined as:
反过来,它使用另一个结构 SOCKADDR,定义为:
Sorry, it's way to complex to post here, as it varies depending on IPv4 vs. IPv6 and the Windows edition... so here is a link to the definition:
抱歉,在这里发帖有点复杂,因为它因 IPv4 与 IPv6 和 Windows 版本而异……所以这里是定义的链接:
http://msdn.microsoft.com/en-us/library/ms740496%28v=VS.85%29.aspx
http://msdn.microsoft.com/en-us/library/ms740496%28v=VS.85%29.aspx
If you haven't gotten dizzy yet like I did and followed through this maze of definitions, you probably noticed that it's a nightmare to retrieve the good old dotted string style of an IP address, as it used to be much easier using GetAdaptersInfo().
如果您还没有像我一样头晕目眩,并没有像我一样完成这个迷宫般的定义,那么您可能已经注意到,检索 IP 地址的旧虚线样式是一场噩梦,因为使用GetAdaptersInfo()过去要容易得多.
My question is: Is there a trulyIP Helper function that can convert IP_ADAPTER_UNICAST_ADDRESS to an IPv4 dotted string (or an IPv6 string)?
我的问题是:是否有真正的IP Helper 函数可以将 IP_ADAPTER_UNICAST_ADDRESS 转换为 IPv4 点分字符串(或 IPv6 字符串)?
采纳答案by Steve Townsend
You can use GetIpAddrTable- the returned data structurecontains a DWORD dwAddr
that is the IPv4 address. The sample code on that first link should show you what you want. Brief excerpt to show you what I mean:
您可以使用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) );
The IP_ADAPTER_UNICAST_ADDRESS
contains a SOCKET_ADDRESS
in Address
, which in turn contains a LPSOCKADDR
in lpSockAddr - you can convert this to the ipv4 string form using WSAAddressToString.
该IP_ADAPTER_UNICAST_ADDRESS
包含SOCKET_ADDRESS
在Address
,其中又包含LPSOCKADDR
在lpSockAddr -你可以将此转换为使用IPv4字符串形式WSAAddressToString。
回答by Will Bickford
Take a look at the documentation for SOCKADDR. That leads us to the documentation for SOCKADDR_STORAGE, which is a helper struct for both IPv4 and IPv6.
查看SOCKADDR的文档。这将我们引向SOCKADDR_STORAGE的文档,它是 IPv4 和 IPv6 的辅助结构。
Quote from the sockaddr documentation:
来自 sockaddr 文档的引用:
Winsock functions using sockaddr are not strictly interpretedto be pointers to a sockaddr structure. The structure is interpreted differently in the context of different address families.
使用 sockaddr 的 Winsock 函数并未严格解释为指向 sockaddr 结构的指针。该结构在不同地址族的上下文中被不同地解释。
For ipv4, you can cast a sockaddr pointer to a sockaddr_in pointer and then access the IPv4 address information from there. Then you can use your favorite string builder to produce a dotted-quad formatted string.
对于 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
I would imagine that you can also cast the address for ipv6 in a similar way given the struct definitions (copied below).
我想您也可以根据结构定义(复制如下)以类似的方式转换 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;
};
回答by Alex
You can simply pass _SOCKET_ADDRESS.lpSockaddr
and _SOCKET_ADDRESS.iSockaddrLength
as lpsaAddress
and dwAddressLength
arguments to WSAAddressToString
function. WSAAddressToString
will do necessary conversion for you, no need to dig deeper.
您可以简单地将_SOCKET_ADDRESS.lpSockaddr
and _SOCKET_ADDRESS.iSockaddrLength
aslpsaAddress
和dwAddressLength
参数传递给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;