背景及問題: 目前很多區域網設備通過mNDS協議實現互聯,IP地址為自動IP段-169.254.x.x,有時候設備廠家提供的API需要通過知曉區域網中的IP地址/設備名,才能連接該設備。這樣要求每個軟體必須配置設備名或者啟動時遍歷所有IP(6w+),不是很方便,這時候可以通過mDNS查詢,自動拿到設 ...
背景及問題:
目前很多區域網設備通過mNDS協議實現互聯,IP地址為自動IP段-169.254.x.x,有時候設備廠家提供的API需要通過知曉區域網中的IP地址/設備名,才能連接該設備。這樣要求每個軟體必須配置設備名或者啟動時遍歷所有IP(6w+),不是很方便,這時候可以通過mDNS查詢,自動拿到設備名,再進行連接,相對便捷,高效。
解決辦法:
在Win10 版本中,windows提供了mDNS查詢的API-DnsStartMulticastQuery,官方定義如下:
其中PMDNS_QUERY_REQUEST定義為
其中各欄位定義如下:
Version | 必須 DNS_QUERY_REQUEST_VERSION1結構版本 |
ulRefCount | 保留。 請勿使用。 |
Query | 表示要通過 mDNS 查詢的名稱的字元串。 |
QueryType | 一個值,該值表示要查詢的記錄的類型。有關可能的值,請參閱DNS_RECORD_TYPE 。 |
QueryOptions | 一個表示查詢選項的 值。 DNS_QUERY_STANDARD 是唯一支持的值。 |
InterfaceIndex | 一個 值,該值包含要播發服務的介面索引。 如果 InterfaceIndex 為 0,則將考慮所有介面。 |
pQueryCallback |
指向類型為 MDNS_QUERY_CALLBACK) 的函數 (的指針,該函數表示每當 mDNS 結果可用時要非同步調用的回調 |
pQueryContext | 指向用戶上下文的指針。 |
fAnswerReceived | 保留。 請勿使用。 |
ulResendCount | 保留。 請勿使用 |
需要註意的是:
Query是所查詢的字元串, pQueryCallback是查詢等到回覆的回調函數,定義如下:
其中PDNS_QUERY_RESULT含有查詢結果DNS_RECORD ,對該結構體進行解析可以得到結果。拿到結果之後需要使用 DnsRecordListFree 函數釋放空間。
示常式序:
#include<Windows.h> #include"mdns.h" #pragma comment(lib, "dnsapi.lib") VOID WINAPI multicastQueryCallback(PVOID pQueryContext, PMDNS_QUERY_HANDLE pQueryHandle, PDNS_QUERY_RESULT pQueryResults) { //pQueryResults為返回結果,對其中的pQueryRecords進行解析 if (pQueryResults->pQueryRecords) { //解析查詢結果 // 釋放空間 dnsRecordListFree(pQueryResults->pQueryRecords,DnsFreeRecordList) ) } void GetQueryResponse(const wchar_t* queryName) { MDNS_QUERY_HANDLE h1; MDNS_QUERY_REQUEST r1; int context = 222; r1.Version = DNS_QUERY_REQUEST_VERSION1; r1.QueryOptions = DNS_QUERY_STANDARD; r1.QueryType = DNS_TYPE_PTR; r1.Query = queryName; r1.pQueryContext = (PVOID)context; r1.InterfaceIndex = 0; r1.pQueryCallback = multicastQueryCallback; DnsStartMulticastQuery(&r1, &h1); Sleep(100); DnsStopMulticastQuery(&h1); }
需要註意的是:
- 目前該API似乎不是很穩定, Release/X64,雙位元組字元串(VS字元集需設置為Unicode)平臺下使用沒有問題
- 此方法為非同步查詢,如果不使用DnsStopMulticastQuery結束查詢,則查詢字元串會一直發送,回調函數會被一直調用。
- pQueryContext可以用來存儲查詢結果(示例中沒有使用)
- QueryOptions設為DNS_QUERY_BYPASS_CACHE可以繞過緩存查詢,每次查詢最新的結果
- 同樣的Release/X64平臺, DnsQuery API也可以查詢,且支持單雙字元串,但是DNS_QUERY_BYPASS_CACHE不起作用;同步查詢,有1s左右延時