windows獲取wifi的bssid(mac地址)進行wifi定位
阿新 • • 發佈:2019-02-14
wifi定位:顧名思義就是利用wifi來進行定位的功能。其原理是通過帶有gps定位功能的裝置接入wifi後,講wifi的bssid資訊連同gps定位結果同時上傳到伺服器,當有其他裝置再次連線這個wifi時,就能大致的推斷出他的位置。
在win8.1後已經提供介面可直接獲取裝置的經定位資訊,當然xp、win7呢?顯然不支援。由此我們就想到有沒有辦法讓他們也能夠定位呢?答案是肯定的!
一、首先你的計算機要支援wifi,不然就扯淡了。看看如何獲取wifi的bssid吧。
#include <wlanapi.h> typedef std::string AString; typedef std::vector<AString> AStringVector; // Need to link with Wlanapi.lib and Ole32.lib #pragma comment(lib, "wlanapi.lib") #pragma comment(lib, "ole32.lib") #pragma comment(lib,"netapi32") AStringVector GetBSSIDs() { AStringVector vecBSSIDs; // Declare and initialize variables. HANDLE hClient = NULL; DWORD dwMaxClient = 2; // DWORD dwCurVersion = 0; DWORD dwResult = 0; DWORD dwRetVal = 0; int iRet = 0; WCHAR GuidString[39] = { 0 }; unsigned int i, j, k; /* variables used for WlanEnumInterfaces */ PWLAN_INTERFACE_INFO_LIST pIfList = NULL; PWLAN_INTERFACE_INFO pIfInfo = NULL; PWLAN_AVAILABLE_NETWORK_LIST pBssList = NULL; PWLAN_AVAILABLE_NETWORK pBssEntry = NULL; int iRSSI = 0; dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient); if (dwResult == ERROR_SUCCESS) { dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList); if (dwResult != ERROR_SUCCESS) { LOG("WlanEnumInterfaces failed with error: %u\n", dwResult); // You can use FormatMessage here to find out why the function failed } else { for (i = 0; i < (int)pIfList->dwNumberOfItems; i++) { pIfInfo = (WLAN_INTERFACE_INFO *)&pIfList->InterfaceInfo[i]; dwResult = WlanGetAvailableNetworkList(hClient, &pIfInfo->InterfaceGuid, 0, NULL, &pBssList); if (dwResult != ERROR_SUCCESS) { LOG("WlanGetAvailableNetworkList failed with error: %u\n", dwResult); dwRetVal = 1; // You can use FormatMessage to find out why the function failed } else { for (j = 0; j < pBssList->dwNumberOfItems; j++) { pBssEntry = (WLAN_AVAILABLE_NETWORK *)& pBssList->Network[j]; PWLAN_BSS_LIST ppWlanBssList; DWORD dwResult2 = WlanGetNetworkBssList(hClient, &pIfInfo->InterfaceGuid, &pBssEntry->dot11Ssid, pBssEntry->dot11BssType, pBssEntry->bSecurityEnabled, NULL, &ppWlanBssList); if (dwResult2 == ERROR_SUCCESS) { for (int z = 0; z < ppWlanBssList->dwNumberOfItems; z++) { WLAN_BSS_ENTRY bssEntry = ppWlanBssList->wlanBssEntries[z]; AString bssid = Printf("%02X:%02X:%02X:%02X:%02X:%02X", bssEntry.dot11Bssid[0], bssEntry.dot11Bssid[1], bssEntry.dot11Bssid[2], bssEntry.dot11Bssid[3], bssEntry.dot11Bssid[4], bssEntry.dot11Bssid[5]); vecBSSIDs.push_back(bssid); } } } } } } } else { LOG("WlanOpenHandle failed with error: %u\n", dwResult); // You can use FormatMessage here to find out why the function failed } if (pBssList != NULL) { WlanFreeMemory(pBssList); pBssList = NULL; } if (pIfList != NULL) { WlanFreeMemory(pIfList); pIfList = NULL; } return vecBSSIDs; }
二、看看如何使用這些bssid吧。
我們以百度的wifi定位介面為例,當然谷歌、新浪等等都有類似的介面,甚至還有收費的。
#include <json/json.h> #include <curl/curl.h> AString url = "http://apis.baidu.com/lbs_repository/wifi/query?coord=wgs84&mac="; size_t write_data(void* buffer, size_t size, size_t nmemb, void *stream) { AString *fptr = (AString*)stream; fptr->append((char*)buffer); return size*nmemb; } void getGeoInfo(const AString &url, const AString &bssid,const AString &appkey) { AString postUrl = url + bssid; CURL *curl; CURLcode res; AString *strRet = new AString; struct curl_slist *headers = NULL; /* init to NULL is important */ headers = curl_slist_append(headers, AString("apikey: "+ m_strAppKey).c_str()); curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, postUrl.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt(curl, CURLOPT_WRITEDATA, strRet); curl_easy_setopt(curl, CURLOPT_HEADER, 1); res = curl_easy_perform(curl); curl_easy_cleanup(curl); if (res != CURLE_OK) { switch (res) { case CURLE_UNSUPPORTED_PROTOCOL: fprintf(stderr, "不支援的協議,由URL的頭部指定\n"); case CURLE_COULDNT_CONNECT: fprintf(stderr, "不能連線到remote主機或者代理\n"); case CURLE_HTTP_RETURNED_ERROR: fprintf(stderr, "http返回錯誤\n"); case CURLE_READ_ERROR: fprintf(stderr, "讀本地檔案錯誤\n"); default: fprintf(stderr, "返回值:%d\n", res); } } AString strResult = *strRet; delete strRet; size_t end_index = strResult.find("\r\n\r\n"); //所以也不需要計算偏移來提高搜尋速度 if (end_index != std::string::npos) { size_t length = strResult.length(); AString strBody = strResult.substr(end_index + 4, length - end_index - 4); AString strHeader = strResult.substr(0, end_index + 4); //正常HTTP頭中 第9-11位為HTTP狀態碼 size_t lenght = strHeader.length(); int _http_code = -1; if (lenght >= 12) { std::string http_code = strHeader.substr(9, 3); try { _http_code = atoi(http_code.c_str()); } catch (...) { _http_code = -1; } } if (_http_code == 200) { Json::Reader reader; Json::Value root; if (reader.parse(strBody, root)) // reader將Json字串解析到root,root將包含Json裡所有子元素 { UInt32 errcode = root["errcode"].asUInt(); UInt32 radius = atoi(root["radius"].asString().c_str()); double lat = atof(root["lat"].asString().c_str()); double lon = atof(root["lon"].asString().c_str()); AString address = root["address"].asString(); if (errcode == 0) { //定位成功 } } } } }
好了,到此為止基本上已經講完了。wifi定位不能作為最終的結果,畢竟資料庫可能不完整或者不實時,定位的結果存在偏差也是很正常的。我們一般還要採取其他方式進行混合定位,比如:基站+wifi+ip+gps等等。
再次希望對需要的人有幫助,謝謝。