wifi定位:顾名思义就是利用wifi来进行定位的功能。其原理是通过带有gps定位功能的设备接入wifi后,讲wifi的bssid信息连同gps定位结果同时上传到服务器,当有其他设备再次连接这个wifi时,就能大致的推断出他的位置。
在win8.1后已经提供接口可直接获取设备的经定位信息,当然xp、win7呢?显然不支持。由此我们就想到有没有办法让他们也能够定位呢?答案是肯定的!
一、首先你的计算机要支持wifi,不然就扯淡了。看看如何获取wifi的bssid吧。
#include
typedef std::string AString;
typedef std::vector 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
#include
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等等。
再次希望对需要的人有帮助,谢谢。