1. 程式人生 > >windows獲取wifi的bssid(mac地址)進行wifi定位

windows獲取wifi的bssid(mac地址)進行wifi定位

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等等。

再次希望對需要的人有幫助,謝謝。