GetAddrInfoExA 函式 (ws2tcpip.h)
GetAddrInfoEx 函式會提供與通訊協議無關的名稱解析,並提供其他參數來限定哪些命名空間提供者應該處理要求。
語法
INT WSAAPI GetAddrInfoExA(
[in, optional] PCSTR pName,
[in, optional] PCSTR pServiceName,
[in] DWORD dwNameSpace,
[in, optional] LPGUID lpNspId,
[in, optional] const ADDRINFOEXA *hints,
[out] PADDRINFOEXA *ppResult,
[in, optional] timeval *timeout,
[in, optional] LPOVERLAPPED lpOverlapped,
[in, optional] LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine,
[out, optional] LPHANDLE lpNameHandle
);
參數
[in, optional] pName
NULL 終止字串的指標,其中包含主機 (節點) 名稱或數值主機位址字串。 對於因特網通訊協議,數值主機位址字串是虛線十進位IPv4位址或IPv6 十六進位位址。
[in, optional] pServiceName
選擇性 NULL 終止字串的指標,其中包含以字串表示的服務名稱或埠號碼。
服務名稱是埠號碼的字串別名。 例如,「HTTP」 是因特網工程工作組 (IETF 所定義的埠 80 別名,) 做為 Web 伺服器用於 HTTP 通訊協定的預設埠。 未指定埠號碼時 ,pServiceName 參數的可能值會列在下列檔案中:
%WINDIR%\system32\drivers\etc\services
[in] dwNameSpace
選擇性命名空間標識碼,決定要查詢哪些命名空間提供者。 傳遞特定命名空間標識碼只會產生支援所查詢指定命名空間的命名空間提供者。 指定 NS_ALL 會導致查詢所有已安裝和作用中的命名空間提供者。
dwNameSpace 參數的選項會列在 Winsock2.h 包含檔案中。 Windows Vista 和更新版本會新增數個命名空間提供者。 您可以安裝其他命名空間提供者,因此只有下列可能的值才可供使用。 可能有許多其他值。
[in, optional] lpNspId
特定命名空間提供者選擇性 GUID 的指標,可在多個命名空間提供者登錄於單一命名空間下,例如 NS_DNS。 傳遞特定命名空間提供者的 GUID 將只會查詢指定的命名空間提供者。 您可以呼叫 WSAEnumNameSpaceProviders 函式來擷取命名空間提供者的 GUID。
[in, optional] hints
addrinfoex 結構的指標,提供呼叫端支援的套接字類型提示。
pHints 參數所指向之 addrinfoex 結構的ai_addrlen、ai_canonname、ai_addr和ai_next成員必須是零或 NULL。 否則 GetAddrInfoEx 函式將會失敗,並 WSANO_RECOVERY。
如需詳細資訊,請參閱。
[out] ppResult
一或多個 addrinfoex 結構鏈接清單的指標,其中包含主機的響應資訊。
[in, optional] timeout
選擇性參數,指出在中止呼叫之前,等候命名空間提供者的回應,以毫秒為單位。
只有在呼叫 GetAddrInfoEx 函式之前,已在來源中定義 UNICODE 或_UNICODE宏時,才支援此參數。 否則,此參數目前是保留的,而且必須設定為 NULL ,因為不支援 逾時 選項。
[in, optional] lpOverlapped
用於異步操作之重疊結構的選擇性指標。
只有在呼叫 GetAddrInfoEx 函式之前,已在來源中定義 UNICODE 或_UNICODE宏時,才支援此參數。
在 Windows 8 和 Windows Server 2012 上,如果未指定 lpCompletionRoutine 參數,則重疊結構的 hEvent 成員必須設定為在異步呼叫時呼叫的手動重設事件。 如果已指定完成例程, hEvent 成員必須是 NULL。 設定 hEvent 指定的事件時,可以藉由呼叫 GetAddrInfoExOverlappedResult 函式來擷取作業的結果。
每當未定義 UNICODE 或 _UNICODE 宏時,在 Windows 8 和 Windows Server 2012 上,此參數目前是保留的,而且必須設定為 NULL。
在 Windows 7 和 Windows Server 2008 R2 或更早版本上,此參數目前已保留,而且必須設定為 NULL ,因為不支援異步操作。
[in, optional] lpCompletionRoutine
異步操作成功完成時要叫用之函式的選擇性指標。
只有在呼叫 GetAddrInfoEx 函式之前,已在來源中定義 UNICODE 或_UNICODE宏時,才支援此參數。
如果指定此參數,它必須是具有下列簽章之函式的指標:
typedef
void
(CALLBACK * LPLOOKUPSERVICE_COMPLETION_ROUTINE)(
__in DWORD dwError,
__in DWORD dwBytes,
__in LPWSAOVERLAPPED lpOverlapped
);
異步操作完成時,將會叫用完成例程,並將 lpOverlapped 參數設定為傳遞至 GetAddrInfoEx 的 lpOverlapped 參數值。 重疊結構的 Pointer 成員會設定為原始呼叫的 ppResult 參數值。 如果 Pointer 成員指向 addrinfoex 結構的非 NULL 指標,則呼叫端必須負責呼叫 FreeAddrInfoEx 以釋放 addrinfoex 結構。 傳遞至完成例程的 dwError 參數將會設定為 Winsock 錯誤碼。 dwBytes 參數保留供日後使用,必須忽略。
每當未定義 UNICODE 或 _UNICODE 宏時,在 Windows 8 和 Windows Server 2012 上,此參數目前是保留的,而且必須設定為 NULL。
在 Windows 7 和 Windows Server 2008 R2 或更早版本上,此參數目前已保留,而且必須設定為 NULL ,因為不支援異步操作。
[out, optional] lpNameHandle
僅用於異步操作的選擇性指標。
只有在呼叫 GetAddrInfoEx 函式之前,已在來源中定義 UNICODE 或_UNICODE宏時,才支援此參數。
在 Windows 8 和 Windows Server 2012 上,如果 GetAddrInfoEx 函式會以異步方式完成,則此字段中傳回的指標可能會與 GetAddrInfoExCancel 函式搭配使用。 當 GetAddrInfoEx 傳回直到呼叫完成例程、觸發事件或使用這個句柄呼叫 GetAddrInfoExCancel 函式時,傳回的句柄有效。
每當未定義 UNICODE 或 _UNICODE 宏時,在 Windows 8 和 Windows Server 2012 上,此參數目前是保留的,而且必須設定為 NULL。
在 Windows 7 和 Windows Server 2008 R2 或更早版本上,此參數目前已保留,而且必須設定為 NULL ,因為不支援異步操作。
傳回值
成功時, GetAddrInfoEx 會傳回 NO_ERROR ( 0) 。 失敗會傳回非零的 Windows Sockets 錯誤碼,如 Windows 套接字錯誤碼中所找到。
GetAddrInfoEx 函式傳回的大部分非零錯誤碼都會對應至 Internet Engineering Task Force (IETF 所概述的一組錯誤) 建議。 下表顯示這些錯誤碼及其 WSA 對等專案。 建議使用 WSA 錯誤碼,因為它們為 Winsock 程式設計人員提供熟悉且完整的錯誤資訊。
錯誤值 | WSA 對等專案 | Description |
---|---|---|
EAI_AGAIN | WSATRY_AGAIN | 發生名稱解析的暫時失敗。 |
EAI_BADFLAGS | WSAEINVAL | 提供無效的參數。 如果任何保留參數不是 NULL,就會傳回此錯誤。 如果為 pHints 參數ai_flags成員提供無效的值,也會傳回此錯誤。 |
EAI_FAIL | WSANO_RECOVERY | 發生無法復原的名稱解析失敗。 |
EAI_FAMILY | WSAEAFNOSUPPORT | 不支援 pHints 參數ai_family成員。 |
EAI_MEMORY | WSA_NOT_ENOUGH_MEMORY | 發生記憶體配置失敗。 |
EAI_NONAME | WSAHOST_NOT_FOUND | 未針對提供的參數解析名稱,或未提供 pName 和 pServiceName 參數。 |
EAI_SERVICE | WSATYPE_NOT_FOUND | pServiceName 參數不支援 pHints 參數的指定ai_socktype成員。 |
EAI_SOCKTYPE | WSAESOCKTNOSUPPORT | 不支援 pHints 參數ai_socktype成員。 |
使用 gai_strerror 函式,根據 GetAddrInfoEx 函式傳回的 EAI 代碼來列印錯誤訊息。 提供gai_strerror函式以符合 IETF 建議,但不是安全線程。 因此,建議使用傳統 Windows Sockets 函式,例如 WSAGetLastError 。
錯誤碼 | 意義 |
---|---|
記憶體不足,無法執行作業。 | |
已使用與要求通訊協定不相容的位址。 如果不支援 pHints 參數所指向的 addrinfoex 結構ai_family成員,就會傳回此錯誤。 | |
提供的引數無效。 如果為 pHints 參數所指向之 addrinfoex 結構ai_flags成員提供無效的值,就會傳回此錯誤。 當 dwNameSpace 參數NS_PNRPNAME或NS_PNRPCLOUD且對等名稱服務未運作時,也會傳回此錯誤。 | |
這個地址家族中不存在對指定通訊端類型的支援。 如果不支援 pHints 參數所指向的 addrinfoex 結構ai_socktype成員,就會傳回此錯誤。 | |
沒有已知的此類主機。 如果未針對提供的參數解析名稱,或未提供 pName 和 pServiceName 參數,則會傳回此錯誤。 | |
要求的名稱有效,但找不到所要求類型的數據。 | |
資料庫尋查期間發生無法復原的錯誤。 如果發生名稱解析中無法復原的錯誤,就會傳回此錯誤。 | |
使用此函式之前,必須先進行成功的 WSAStartup 呼叫。 | |
不知道這類服務。 在指定的名稱空間中找不到服務。 如果在 dwNameSpace 參數中指定的命名空間找不到 pName 或 pServiceName 參數,或未安裝 dwNameSpace 參數中指定的命名空間,就會傳回這個錯誤。 | |
這通常為主機名稱解析期間的暫時錯誤,表示本機伺服器未收到授權伺服器的回應。 發生名稱解析暫時失敗時,就會傳回此錯誤。 | |
找不到指定的類別。 pServiceName 參數不支援 pHints 參數所指向之 addrinfoex 結構的指定ai_socktype成員。 |
備註
GetAddrInfoEx 函式提供從主機名到地址的通訊協定獨立轉譯,以及從服務名稱到埠號碼。 GetAddrInfoEx 函式是 getaddrinfo 和 GetAddrInfoW 函式的增強版本。 GetAddrInfoEx 函式允許指定命名空間提供者來解析查詢。
GetAddrInfoEx 函式會匯總並傳回多個命名空間提供者的結果,除非指定特定的命名空間提供者。 為了與 IPv6 和 IPv4 通訊協定搭配使用,名稱解析可以是域名系統 (DNS) 、本機 主機 檔案、電子郵件提供者 (NS_EMAIL 命名空間) 或其他命名機制。
定義 UNICODE 或_UNICODE時, GetAddrInfoEx 會定義為 GetAddrInfoExW,這是此函式的 Unicode 版本。 字串參數會定義至 PWSTR 資料類型,並使用 ADDRINFOEXW 結構。 在 Windows 8 和 Windows Server 2012 上, 逾時、 lpOverlapped、 lpCompletionRoutine 和 lpNameHandle 參數可用來呼叫 GetAddrInfoEx 函式,以便以異步方式完成。
未定義 UNICODE 或_UNICODE時, GetAddrInfoEx 會定義為 GetAddrInfoExA,這是此函式的 ANSI 版本。 字串參數屬於 PCSTR 數據類型,並使用 ADDRINFOEXA 結構。 timeout、lpOverlapped、lpCompletionRoutine 和 lpNameHandle 參數必須設定為 NULL。
pName 或 pServiceName 參數的一或兩者都必須指向 NULL 終止的字串。 通常會提供這兩者。
成功時,ppResult 參數會傳回 addrinfoex 結構的連結清單。 您可以依照每個傳回 addrinfoex 結構的ai_next成員中提供的指標來處理清單,直到遇到 NULL 指標為止。 在每個傳回 的 addrinfoex 結構中, ai_family、 ai_socktype和 ai_protocol 成員會對應到 套接字 或 WSASocket 函數調用中的個別自變數。 此外,每個傳回 addrinfoex 結構中的ai_addr成員都會指向填入的套接字地址結構,其ai_addrlen成員中指定的長度。
如果 pName 參數指向電腦名稱,則會傳回可用來做為來源地址的電腦的所有永久位址。 在 Windows Vista 和更新版本上,這些位址會包含 GetUnicastIpAddressTable 或 GetUnicastIpAddressEntry 函式傳回的所有單播 IP 位址, 其中 SkipAsSource 成員在 MIB_UNICASTIPADDRESS_ROW 結構中設定為 false。
如果 pName 參數指向等於 「localhost」 的字串,則會傳回本機電腦上的所有回送位址。
如果 pName 參數包含空字串,則會傳回本機電腦上所有已註冊的位址。
如果 pName 參數指向等於 「. 的字串,在 Windows Server 2003 和更新版本上。localmachine“,會傳回本機計算機上所有已註冊的位址。
如果 pName 參數參考叢集虛擬伺服器名稱,則只會傳回虛擬伺服器位址。 在 Windows Vista 和更新版本上,這些位址會包含 GetUnicastIpAddressTable 或 GetUnicastIpAddressEntry 函式傳回的所有單播 IP 位址, 其中 SkipAsSource 成員在 MIB_UNICASTIPADDRESS_ROW 結構中設定為 true。 如需叢集的詳細資訊,請參閱 Windows 叢集 。
Windows 7 Service Pack 1 (SP1) 和 Windows Server 2008 R2 with Service Pack 1 (SP1) 新增支援至 Netsh.exe,以在 IP 位址上設定 SkipAsSource 屬性。 這也會變更行為,如此一來,如果 MIB_UNICASTIPADDRESS_ROW 結構中的SkipAsSource成員設定為 false,IP 位址將會在 DNS 中註冊。 如果 SkipAsSource 成員設定為 true,則不會在 DNS 中註冊 IP 位址。
Hotfix 適用於 Windows 7 和 Windows Server 2008 R2,可新增對 Netsh.exe 的支援,以在 IP 位址上設定 SkipAsSource 屬性。 此 Hotfix 也會變更行為,如此一來,如果 MIB_UNICASTIPADDRESS_ROW 結構中的 SkipAsSource 成員設定為 false,IP 位址將會在 DNS 中註冊。 如果 SkipAsSource 成員設定為 true,則不會在 DNS 中註冊 IP 位址。 如需詳細資訊,請參閱 知識庫 (KB) 2386184。
Windows Vista 的 Service Pack 2 (SP2) 和 Windows Server 2008 Service Pack 2 (SP2) 也提供類似的 Hotfix,可新增對 Netsh.exe 的支援,以在 IP 位址上設定 SkipAsSource 屬性。 此 Hotfix 也會變更行為,如此一來,如果 MIB_UNICASTIPADDRESS_ROW 結構中的 SkipAsSource 成員設定為 false,IP 位址將會在 DNS 中註冊。 如果 SkipAsSource 成員設定為 true,則不會在 DNS 中註冊 IP 位址。
GetAddrInfoEx 函式的呼叫端可以提供 pHints 參數所指向之 addrinfoex 結構所支援的套接字類型提示。 使用 pHints 參數時,下列規則會套用至其相關聯的 addrinfoex 結構:
- ai_family的 AF_UNSPEC 值表示呼叫端只會接受AF_INET和AF_INET6位址系列。 請注意, AF_UNSPEC 和 PF_UNSPEC 相同。
- ai_socktype值為零 , 表示呼叫端將接受任何套接字類型。
- ai_protocol的值為零,表示呼叫端將接受任何通訊協定。
- ai_addrlen成員必須設定為零。
- ai_canonname成員必須設定為NULL。
- ai_addr成員必須設定為NULL。
- ai_next成員必須設定為NULL。
pHints 參數中提供的 addrinfoex 結構中的其他值會指出特定需求。 例如,如果呼叫端只處理 IPv4 且未處理 IPv6, 則ai_family 成員應該設定為 AF_INET。 針對另一個範例,如果呼叫端只處理 TCP 且未處理 UDP, 則ai_socktype 成員應該設定為 SOCK_STREAM。
如果 pHints 參數是 NULL 指標,GetAddrInfoEx 函式會將它視為 pHints 中的 addrinfoex 結構已初始化,且其ai_family成員設定為 AF_UNSPEC,而所有其他成員都設定為 NULL 或零。
從服務呼叫 GetAddrInfoEx 時,如果作業是呼叫服務的用戶進程結果,服務應該模擬使用者。 這是為了允許正確強制執行安全性。
GetAddrInfoEx 函式可用來將IP位址的文字字串表示轉換成 addrinfoex 結構,其中包含IP位址和其他資訊的sockaddr結構。 若要以這種方式使用,pName 參數所指向的字串必須包含IP位址的文字表示,而 pHints 參數所指向的addrinfoex結構必須設定ai_flags成員中設定AI_NUMERICHOST旗標。 pName 參數所指向的字串可能包含 IPv4 或 IPv6 位址的文字表示。 文字 IP 位址會轉換成 ppResult 參數所指向的 addrinfoex 結構。 傳回的 addrinfoex 結構包含 IP 位址 的 sockaddr 結構,以及 IP 位址的其他資訊。
多個命名空間提供者可以安裝在相同命名空間的本機計算機上。 例如,基底 Windows TCP/IP 網路軟體會註冊NS_DNS命名空間。 Microsoft Forefront Threat Management Gateway (TMG) 和較舊的 Microsoft Internet Security and Acceleration (ISA) Server 包含同時註冊NS_DNS命名空間的防火牆客戶端軟體。 當 dwNameSpace 參數設定為值 (NS_DNS 時,例如,) 和 lpNspId 參數為 NULL 時, GetAddrInfoEx 函式傳回的結果是所有命名空間提供者的合併結果,這些命名空間提供者都會註冊具有重複結果的命名空間。 只有在查詢單一命名空間提供者時, lpNspId 參數應該設定為特定命名空間提供者的 GUID。
如果 pNameSpace 參數設定為 NS_ALL,則會合併並傳回查詢所有命名空間提供者的結果。 在此情況下,如果多個命名空間提供者傳回相同的資訊,則 ppResult 參數所指向的結果可能會傳回重複的回應。
在 Windows 8 和 Windows Server 2012 上,如果 GetAddrInfoEx 函式會以異步方式完成, lpNameHandle 參數中傳回的指標可能會與 GetAddrInfoExCancel 函式搭配使用。 當 GetAddrInfoEx 傳回直到呼叫完成例程、觸發事件或使用這個句柄呼叫 GetAddrInfoExCancel 函式時,傳回的句柄有效。
從動態配置釋放地址資訊
由 ppResult 參數指向之 GetAddrInfoEx 函式所傳回的所有資訊都會動態配置,包括 addrinfoex 結構、套接字地址結構,以及 addrinfoex 結構所指向的標準主機名字符串。 成功呼叫此函式所配置的記憶體必須釋放,且後續呼叫 FreeAddrInfoEx。範例程序代碼
下列範例示範 如何使用 GetAddrInfoEx 函式。#ifndef UNICODE
#define UNICODE
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <objbase.h>
#include <stdio.h>
// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")
// Need to link with Ole32.lib to print GUID
#pragma comment(lib, "ole32.lib")
int __cdecl wmain(int argc, wchar_t ** argv)
{
//-----------------------------------------
// Declare and initialize variables
WSADATA wsaData;
int iResult;
DWORD dwRetval;
int i = 1;
DWORD dwNamespace = NS_ALL;
LPGUID lpNspid = NULL;
ADDRINFOEX *result = NULL;
ADDRINFOEX *ptr = NULL;
ADDRINFOEX hints;
// LPSOCKADDR sockaddr_ip;
struct sockaddr_in *sockaddr_ipv4;
struct sockaddr_in6 *sockaddr_ipv6;
// DWORD ipbufferlength = 46;
wchar_t ipstringbuffer[46];
// variables needed to print namespace provider GUID
int iRet = 0;
WCHAR GuidString[40] = { 0 };
// Validate the parameters
if (argc != 4) {
wprintf(L"usage: %ws <hostname> <servicename> <namespace>\n", argv[0]);
wprintf(L"getaddrinfoex provides protocol-independent translation\n");
wprintf(L" from a host name to an IP address\n");
wprintf(L"%ws example usage\n", argv[0]);
wprintf(L" %ws www.contoso.com 0 12\n", argv[0]);
wprintf(L" looks up the www.contoso.com in the NS_DNS namespace\n",
argv[0]);
return 1;
}
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
wprintf(L"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;
dwNamespace = (DWORD) _wtoi(argv[3]);
wprintf(L"Calling GetAddrInfoEx with following parameters:\n");
wprintf(L"\tName = %ws\n", argv[1]);
wprintf(L"\tServiceName (or port) = %ws\n", argv[2]);
wprintf(L"\tNamespace = %s (", argv[3]);
switch (dwNamespace) {
case NS_ALL:
wprintf(L"(NS_ALL)\n");
break;
case NS_DNS:
wprintf(L"(NS_DNS)\n");
break;
case NS_NETBT:
wprintf(L"NS_NETBT");
break;
case NS_WINS:
wprintf(L"NS_WINS");
break;
case NS_NLA:
wprintf(L"NS_NLA");
break;
case NS_BTH:
wprintf(L"NS_BTH");
break;
case NS_NTDS:
wprintf(L"NS_NTDS");
break;
case NS_EMAIL:
wprintf(L"NS_EMAIL");
break;
case NS_PNRPNAME:
wprintf(L"NS_PNRPNAME");
break;
case NS_PNRPCLOUD:
wprintf(L"NS_PNRPCLOUD");
break;
default:
wprintf(L"Other");
break;
}
wprintf(L")\n\n");
//--------------------------------
// Call getaddrinfoex(). If the call succeeds,
// the result variable will hold a linked list
// of addrinfo structures containing response
// information
dwRetval =
GetAddrInfoEx(argv[1], argv[2], dwNamespace, lpNspid, &hints, &result,
NULL, NULL, NULL, NULL);
if (dwRetval != 0) {
wprintf(L"GetAddrInfoEx failed with error: %d\n", dwRetval);
WSACleanup();
return 1;
}
wprintf(L"GetAddrInfoEx returned success\n");
// Retrieve each address and print out the hex bytes
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
wprintf(L"GetAddrInfoEx response %d\n", i++);
wprintf(L"\tFlags: 0x%x\n", ptr->ai_flags);
wprintf(L"\tFamily: ");
switch (ptr->ai_family) {
case AF_UNSPEC:
wprintf(L"Unspecified\n");
break;
case AF_INET:
wprintf(L"AF_INET (IPv4)\n");
// the InetNtop function is available on Windows Vista and later
sockaddr_ipv4 = (struct sockaddr_in *) ptr->ai_addr;
wprintf(L"\tIPv4 address %ws\n",
InetNtop(AF_INET, &sockaddr_ipv4->sin_addr, ipstringbuffer,
46));
// We could also use the WSAAddressToString function
// 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)
// wprintf(L"WSAAddressToString failed with %u\n", WSAGetLastError() );
// else
// wprintf(L"\tIPv4 address %ws\n", ipstringbuffer);
break;
case AF_INET6:
wprintf(L"AF_INET6 (IPv6)\n");
// the InetNtop function is available on Windows Vista and later
sockaddr_ipv6 = (struct sockaddr_in6 *) ptr->ai_addr;
wprintf(L"\tIPv6 address %ws\n",
InetNtop(AF_INET6, &sockaddr_ipv6->sin6_addr,
ipstringbuffer, 46));
// We could also use WSAAddressToString which also returns the scope ID
// 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)
// wprintf(L"WSAAddressToString failed with %u\n", WSAGetLastError() );
//else
// wprintf(L"\tIPv6 address %ws\n", ipstringbuffer);
break;
default:
wprintf(L"Other %ld\n", ptr->ai_family);
break;
}
wprintf(L"\tSocket type: ");
switch (ptr->ai_socktype) {
case 0:
wprintf(L"Unspecified\n");
break;
case SOCK_STREAM:
wprintf(L"SOCK_STREAM (stream)\n");
break;
case SOCK_DGRAM:
wprintf(L"SOCK_DGRAM (datagram) \n");
break;
case SOCK_RAW:
wprintf(L"SOCK_RAW (raw) \n");
break;
case SOCK_RDM:
wprintf(L"SOCK_RDM (reliable message datagram)\n");
break;
case SOCK_SEQPACKET:
wprintf(L"SOCK_SEQPACKET (pseudo-stream packet)\n");
break;
default:
wprintf(L"Other %ld\n", ptr->ai_socktype);
break;
}
wprintf(L"\tProtocol: ");
switch (ptr->ai_protocol) {
case 0:
wprintf(L"Unspecified\n");
break;
case IPPROTO_TCP:
wprintf(L"IPPROTO_TCP (TCP)\n");
break;
case IPPROTO_UDP:
wprintf(L"IPPROTO_UDP (UDP) \n");
break;
default:
wprintf(L"Other %ld\n", ptr->ai_protocol);
break;
}
wprintf(L"\tLength of this sockaddr: %d\n", ptr->ai_addrlen);
wprintf(L"\tCanonical name: %s\n", ptr->ai_canonname);
if (ptr->ai_blob == NULL)
wprintf(L"\tBlob: (null)\n");
else
wprintf(L"\tLength of the blob: %u\n",
(DWORD) ptr->ai_bloblen);
if (ptr->ai_provider == NULL)
wprintf(L"\tNamespace provider GUID: (null)\n");
else {
iRet =
StringFromGUID2(*(ptr->ai_provider), (LPOLESTR) & GuidString,
39);
// For c rather than C++ source code, the above line needs to be
// iRet = StringFromGUID2(&ptr.ai_provider, (LPOLESTR) &GuidString, 39);
if (iRet == 0)
wprintf(L"StringFromGUID2 failed\n");
else {
wprintf(L"\tNamespace provider: %ws\n", GuidString);
}
}
}
FreeAddrInfoEx(result);
WSACleanup();
return 0;
}
下列範例示範如何使用 GetAddrInfoEx 函式異步將名稱解析為 IP 位址。
//
// This sample demonstrates how to use asynchronous GetAddrInfoEx to
// resolve a name to an IP address.
//
// ResolveName <QueryName>
//
#ifndef UNICODE
#define UNICODE
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")
#define MAX_ADDRESS_STRING_LENGTH 64
//
// Asynchronous query context structure.
//
typedef struct _QueryContext
{
OVERLAPPED QueryOverlapped;
PADDRINFOEX QueryResults;
HANDLE CompleteEvent;
}QUERY_CONTEXT, *PQUERY_CONTEXT;
VOID
WINAPI
QueryCompleteCallback(
_In_ DWORD Error,
_In_ DWORD Bytes,
_In_ LPOVERLAPPED Overlapped
);
int
__cdecl
wmain(
_In_ int Argc, PWCHAR Argv[]
)
{
INT Error = ERROR_SUCCESS;
WSADATA wsaData;
BOOL IsWSAStartupCalled = FALSE;
ADDRINFOEX Hints;
QUERY_CONTEXT QueryContext;
HANDLE CancelHandle = NULL;
DWORD QueryTimeout = 5 * 1000; // 5 seconds
ZeroMemory(&QueryContext, sizeof(QueryContext));
//
// Validate the parameters
//
if (Argc != 2)
{
wprintf(L"Usage: ResolveName <QueryName>\n");
goto exit;
}
//
// All Winsock functions require WSAStartup() to be called first
//
Error = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (Error != 0)
{
wprintf(L"WSAStartup failed with %d\n", Error);
goto exit;
}
IsWSAStartupCalled = TRUE;
ZeroMemory(&Hints, sizeof(Hints));
Hints.ai_family = AF_UNSPEC;
//
// Note that this is a simple sample that waits/cancels a single
// asynchronous query. The reader may extend this to support
// multiple asynchronous queries.
//
QueryContext.CompleteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (QueryContext.CompleteEvent == NULL)
{
Error = GetLastError();
wprintf(L"Failed to create completion event: Error %d\n", Error);
goto exit;
}
//
// Initiate asynchronous GetAddrInfoExW.
//
// Note GetAddrInfoEx can also be invoked asynchronously using an event
// in the overlapped object (Just set hEvent in the Overlapped object
// and set NULL as completion callback.)
//
// This sample uses the completion callback method.
//
Error = GetAddrInfoExW(Argv[1],
NULL,
NS_DNS,
NULL,
&Hints,
&QueryContext.QueryResults,
NULL,
&QueryContext.QueryOverlapped,
QueryCompleteCallback,
&CancelHandle);
//
// If GetAddrInfoExW() returns WSA_IO_PENDING, GetAddrInfoExW will invoke
// the completion routine. If GetAddrInfoExW returned anything else we must
// invoke the completion directly.
//
if (Error != WSA_IO_PENDING)
{
QueryCompleteCallback(Error, 0, &QueryContext.QueryOverlapped);
goto exit;
}
//
// Wait for query completion for 5 seconds and cancel the query if it has
// not yet completed.
//
if (WaitForSingleObject(QueryContext.CompleteEvent,
QueryTimeout) == WAIT_TIMEOUT )
{
//
// Cancel the query: Note that the GetAddrInfoExCancelcancel call does
// not block, so we must wait for the completion routine to be invoked.
// If we fail to wait, WSACleanup() could be called while an
// asynchronous query is still in progress, possibly causing a crash.
//
wprintf(L"The query took longer than %d seconds to complete; "
L"cancelling the query...\n", QueryTimeout/1000);
GetAddrInfoExCancel(&CancelHandle);
WaitForSingleObject(QueryContext.CompleteEvent,
INFINITE);
}
exit:
if (IsWSAStartupCalled)
{
WSACleanup();
}
if (QueryContext.CompleteEvent)
{
CloseHandle(QueryContext.CompleteEvent);
}
return Error;
}
//
// Callback function called by Winsock as part of asynchronous query complete
//
VOID
WINAPI
QueryCompleteCallback(
_In_ DWORD Error,
_In_ DWORD Bytes,
_In_ LPOVERLAPPED Overlapped
)
{
PQUERY_CONTEXT QueryContext = NULL;
PADDRINFOEX QueryResults = NULL;
WCHAR AddrString[MAX_ADDRESS_STRING_LENGTH];
DWORD AddressStringLength;
UNREFERENCED_PARAMETER(Bytes);
QueryContext = CONTAINING_RECORD(Overlapped,
QUERY_CONTEXT,
QueryOverlapped);
if (Error != ERROR_SUCCESS)
{
wprintf(L"ResolveName failed with %d\n", Error);
goto exit;
}
wprintf(L"ResolveName succeeded. Query Results:\n");
QueryResults = QueryContext->QueryResults;
while(QueryResults)
{
AddressStringLength = MAX_ADDRESS_STRING_LENGTH;
WSAAddressToString(QueryResults->ai_addr,
(DWORD)QueryResults->ai_addrlen,
NULL,
AddrString,
&AddressStringLength);
wprintf(L"Ip Address: %s\n", AddrString);
QueryResults = QueryResults->ai_next;
}
exit:
if (QueryContext->QueryResults)
{
FreeAddrInfoEx(QueryContext->QueryResults);
}
//
// Notify caller that the query completed
//
SetEvent(QueryContext->CompleteEvent);
return;
}
國際化功能變數名稱
因特網主機名通常包含一組非常受限的字元:- 大寫和小寫的英文 ASCII 字母。
- 0 到 9 位數。
- ASCII 連字元字元。
隨著因特網的成長,需要識別 ASCII 字元集未表示之其他語言的因特網主機名。 有助於此需求的標識符,並允許 Unicode (Unicode) 的非 ASCII 字元表示為特殊 ASCII 字元字串,稱為國際功能變數名稱 (IDN) 。 在應用程式 (IDNA) 中將域名國際化的機制,可用來以標準方式處理 IDN。 IDN 和 IDNA 的規格記載於 INTERNET Engineering Task Force (IETF) 所發佈的 RFC 3490、 RTF 5890 和 RFC 6365 中。
在 Windows 8 和 Windows Server 2012 上, GetAddrInfoEx 函式支持國際化功能變數名稱 (IDN) 剖析套用至 pName 參數中傳遞的名稱。 Winsock 會執行 Punycode/IDN 編碼和轉換。 您可以使用下面討論 的AI_DISABLE_IDN_ENCODING 旗標來停用此行為。
在 Windows 7 和 Windows Server 2008 R2 或更早版本上, GetAddrInfoEx 函式目前不支援套用至 pName 參數中所傳遞名稱的 IDN 剖析。 GetAddrInfoEx 函式的寬字元版本不會使用 Punycode,根據 RFC 3490 轉換 IDN Punycode 格式。 查詢 DNS 時 ,GetAddrInfoEx 函式的寬字元版本會以 UTF-8 格式編碼 Unicode 名稱,這是企業環境中 Microsoft DNS 伺服器所使用的格式。
Windows Vista 和更新版本的數個函式支援在 IDN 中的 Unicode 標籤與其 ASCII 對等專案之間的轉換。 每個 Unicode 標籤的結果表示只包含 ASCII 字元,如果 Unicode 標籤包含任何非 ASCII 字元,則開頭為 xn-- 前置詞。 原因是支援因特網上的現有 DNS 伺服器,因為某些 DNS 工具和伺服器僅支援 ASCII 字元, (請參閱 RFC 3490) 。
IdnToAscii 函式會使用 Punycode,使用 RFC 3490 中定義的標準演算法,將 IDN 轉換成原始 Unicode 字串的 ASCII 表示法。 IdnToUnicode 函式會將IDN的 ASCII形式轉換為一般的 Unicode UTF-16 編碼語法。 如需相關草稿標準的詳細資訊和連結,請參閱 處理國際化功能變數名稱 (IDN) 。
IdnToAscii 函式可用來將 IDN 名稱轉換成 ASCII 形式,然後當未) 定義 UNICODE 和 _UNICODE 時,當未定義 UNICODE 和 _UNICODE時,這個 (函式的 ASCII 版本會傳遞至 GetAddrInfoEx 函式。 若要將此 IDN 名稱傳遞至 GetAddrInfoEx 函式,當 UNICODE 或_UNICODE定義) 時, (使用此函式的寬字元版本時,您可以使用 MultiByteToWideChar 函數將 CHAR 字串轉換成 WCHAR 字串。
在 hints 參數中使用ai_flags
hints 參數中提供的選擇性 addrinfoex 結構ai_flags成員中的旗標會修改函式的行為。
這些旗標位定義於適用於 Windows 7 的 Microsoft Windows 軟體開發工具包 (SDK) Ws2def.h 頭檔中。 這些旗標位定義於 Windows SDK for Windows Server 2008 和 Windows Vista 上的 Ws2tcpip.h 頭檔中。 這些旗標位定義於適用於 Windows Server 2003 和 Windows XP 的 Platform Software Development Kit (SDK) Ws2tcpip.h 頭檔中。
旗標位可以是下列各項的組合:
標幟位 | Description |
---|---|
AI_PASSIVE |
設定 AI_PASSIVE 旗標表示呼叫端想要在系 結 函式的呼叫中使用傳回的套接字地址結構。 設定 AI_PASSIVE 旗標且 pName 為 NULL 指標時,套接字地址結構的IP位址部分會設定為 IPv4 位址 的 INADDR_ANY, 而 IPv6 位址IN6ADDR_ANY_INIT。
未設定 AI_PASSIVE 旗標時,傳回的套接字地址結構已準備好呼叫連線導向通訊協定的 連線 函式,或準備好呼叫 連線、 傳送或傳送無連線通訊協定的 函 式。 如果 pName 參數在此案例中是 NULL 指標,套接字地址結構的 IP 位址部分會設定為回送位址。 |
AI_CANONNAME |
如果未使用AI_CANONNAME或AI_NUMERICHOST,GetAddrInfoEx 函式會嘗試解析。 如果傳遞常值字串 GetAddrInfoEx 嘗試轉換字串串,而且如果傳遞主機名, GetAddrInfoEx 函式會嘗試將名稱解析為位址或多個位址。
設定 AI_CANONNAME 位時, pName 參數不能是 NULL。 否則 GetAddrInfoEx 函式將會失敗,並 WSANO_RECOVERY。 設定AI_CANONNAME位且 GetAddrInfoEx 函式傳回成功時,ppResult 參數中的ai_canonname成員會指向包含指定節點標準名稱的 NULL 終止字元串。 注意設定AI_CANONNAME旗標時,GetAddrInfoEx 函式可以傳回成功,但相關聯 addrinfo 結構中的ai_canonname成員為 NULL。 因此,建議使用AI_CANONNAME旗標包括測試相關聯 addrinfoex 結構中的ai_canonname成員是否為 NULL。
|
AI_NUMERICHOST | 設定 AI_NUMERICHOST 位時, pName 參數必須包含非 NULL 數值主機位址字串,否則會傳回 EAI_NONAME 錯誤。 此旗標可防止呼叫名稱解析服務。 |
AI_NUMERICSERV |
設定 AI_NUMERICSERV 位時, pServiceName 參數必須包含非 NULL 數值埠號碼,否則會傳回 EAI_NONAME 錯誤。 此旗標可防止呼叫名稱解析服務。
AI_NUMERICSERV旗標是在 Windows SDK for Windows Vista 和更新版本上定義。 Microsoft 提供者不支援 AI_NUMERICSERV 旗標。 |
AI_ALL |
如果 已設定AI_ALL 位,則會針對具有 AI_V4MAPPED的 IPv6 位址和 IPv4 位址提出要求。
AI_ALL旗標是在 Windows SDK for Windows Vista 和更新版本上定義。 Windows Vista 和更新版本支援 AI_ALL 旗標。 |
AI_ADDRCONFIG |
如果 已設定AI_ADDRCONFIG 位, GetAddrInfoEx 只會在設定全域位址時解析。 如果指定 了AI_ADDRCONFIG 旗標,則只有在本機系統上設定IPv4位址時,才會傳回IPv4 位址,而且只有在本機系統上設定IPv6 位址時,才會傳回 IPv6 位址。 IPv4 或 IPv6 回送位址不會被視為有效的全域位址。
AI_ADDRCONFIG旗標是在 Windows SDK for Windows Vista 和更新版本上定義。 Windows Vista 和更新版本支援 AI_ADDRCONFIG 旗標。 |
AI_V4MAPPED |
如果 已設定AI_V4MAPPED 位,且 IPv6 位址的要求失敗,則會對 IPv4 位址提出名稱服務要求,而且這些位址會轉換成 IPv4 對應 IPv6 位址格式。
AI_V4MAPPED旗標是在 Windows SDK for Windows Vista 和更新版本上定義。 Windows Vista 和更新版本支援 AI_V4MAPPED 旗標。 |
AI_NON_AUTHORITATIVE |
如果 已設定AI_NON_AUTHORITATIVE 位, 則NS_EMAIL 命名空間提供者會同時傳回授權和非授權結果。 如果未設定 AI_NON_AUTHORITATIVE 位, 則NS_EMAIL 命名空間提供者只會傳回授權結果。
AI_NON_AUTHORITATIVE旗標是在 Windows SDK for Windows Vista 和更新版本上定義。 Windows Vista 和更新版本支援 AI_NON_AUTHORITATIVE 旗標,並僅適用於 NS_EMAIL 命名空間。 |
AI_SECURE |
如果 已設定AI_SECURE 位, NS_EMAIL 命名空間提供者會傳回以增強安全性取得的結果,以將可能的詐騙降到最低。
AI_SECURE旗標是在 Windows SDK for Windows Vista 和更新版本上定義。 Windows Vista 和更新版本支援 AI_SECURE 旗標,僅適用於 NS_EMAIL 命名空間。 |
AI_RETURN_PREFERRED_NAMES |
如果 已設定AI_RETURN_PREFERRED_NAMES ,則不應該在 pName 參數中提供名稱。 NS_EMAIL命名空間提供者會傳回發行集的慣用名稱。
AI_RETURN_PREFERRED_NAMES旗標是在 Windows SDK for Windows Vista 和更新版本上定義。 Windows Vista 和更新版本支援 AI_RETURN_PREFERRED_NAMES 旗標,僅適用於 NS_EMAIL 命名空間。 |
AI_FQDN |
如果 已設定AI_FQDN ,且指定單一卷標 (一般名稱 ) ,GetAddrInfoEx 將會傳回最終解析名稱的完整功能變數名稱。 完整功能變數名稱會在相關聯 addrinfoex 結構的ai_canonname成員中傳回。 這與傳回 DNS 中註冊標準名稱的 AI_CANONNAME 位旗標不同,可能與一般名稱解析為的完整功能變數名稱不同。
設定 AI_FQDN 位時, pName 參數不能是 NULL。 否則 GetAddrInfoEx 函式將會失敗,並 WSANO_RECOVERY。 在 Windows 8 和 Windows Server 2012 上,可以設定 AI_FQDN 和 AI_CANONNAME 位。 如果使用 AI_FQDN 和 AI_CANONNAME 位呼叫 GetAddrInfoEx 函式,ppResult 參數會傳回 addrinfoex2 結構的指標,而不是 addrinfoex 結構。 在 Windows 7 和 Windows Server 2008 R2 上,只能設定其中一個 AI_FQDN 和 AI_CANONNAME 位。 如果兩個旗標都出現EAI_BADFLAGS,GetAddrInfoEx 函式將會失敗。 Windows 7: AI_FQDN旗標是在 Windows SDK for Windows 7 和更新版本上定義。 Windows 7 和更新版本支援 AI_FQDN 旗標。 |
AI_FILESERVER |
如果 已設定AI_FILESERVER ,這是要查詢的主機名用於檔案共用案例的命名空間提供者提示。 命名空間提供者可能會忽略此提示。
Windows 7: AI_FILESERVER旗標是在 Windows SDK for Windows 7 和更新版本上定義。 Windows 7 和更新版本支援 AI_FILESERVER 旗標。 |
AI_DISABLE_IDN_ENCODING |
如果 已設定AI_DISABLE_IDN_ENCODING ,這會在 GetAddrInfoEx 函式所呼叫的名稱解析函式中使用 Punycode 停用自動國際功能變數名稱編碼。
Windows 8: AI_DISABLE_IDN_ENCODING旗標是在 Windows SDK for Windows 8 和更新版本上定義。 Windows 8 和更新版本支援 AI_DISABLE_IDN_ENCODING 旗標。 |
注意
ws2tcpip.h 標頭會根據 UNICODE 預處理器常數的定義,將 GetAddrInfoEx 定義為別名,自動選取此函式的 ANSI 或 Unicode 版本。 混合使用編碼中性別名與非編碼中性的程序代碼,可能會導致編譯或運行時間錯誤不符。 如需詳細資訊,請參閱 函式原型的慣例。
規格需求
需求 | 值 |
---|---|
最低支援的用戶端 | Windows XP [傳統型應用程式 |UWP 應用程式] |
最低支援的伺服器 | Windows Server 2008 [傳統型應用程式 |UWP 應用程式] |
目標平台 | Windows |
標頭 | ws2tcpip.h |
程式庫 | Ws2_32.lib |
Dll | Ws2_32.dll |