问题一:WiFi名显示重复
在前端页面使用WiFi网络扫描功能,会产生多个重复的UUID,用NetworkManager工具并未产生类似情况


问题定位
寻找接口:networkmanage/wifiInfo
cpp
int Handler::getWifi(const HttpContextPtr &ctx) {
hv::Json j;
j["msg"] = "success";
j["code"] = HTTP_STATUS_OK;
string info;
int ret = selectDeployCode(dbCodeToString(SysDeployCode::WIFI_INFO), info);
if (ret < 0) {
return response_status(ctx, HTTP_STATUS_INTERNAL_SERVER_ERROR, "select error");
}
j["data"]["wifiInfo"] = hv::Json::parse(info);
ret = selectDeployCode(dbCodeToString(SysDeployCode::ONLINE), info);
if (ret < 0) {
return response_status(ctx, HTTP_STATUS_INTERNAL_SERVER_ERROR, "select error");
}
j["data"]["online"] = stringToBool(info);
return ctx->sendJson(j);
}
wifi功能实现代码:
cpp
int Wifi::scanWifi() {
string ssids;
string scanCmd("nmcli -f SIGNAL,SSID d wifi list");
if (!myPopen(scanCmd, ssids)) {
hloge("failed to scan ssid");
return -1;
}
stringstream ss;
ss << ssids;
string item;
getline(ss, item, '\n');
while(getline(ss, item, '\n')) {
int pos = item.find_first_of(' ');
if (pos == string::npos) {
hloge("wifi scan result error");
ssidVec.clear();
return -1;
}
string signal = item.substr(0, pos);
int sig = 0;
if(stringIsNumber(signal))
sig = stoi(signal);
int sigLevel = 0;
if (sig <= 20) {
sigLevel = 0;
} else if (sig > 20 && sig <= 40) {
sigLevel = 1;
} else if (sig > 40 && sig <= 60) {
sigLevel = 2;
} else if (sig > 60 && sig <= 80) {
sigLevel = 3;
} else {
sigLevel = 4;
}
while(item[pos] == ' ') {
pos++;
}
string itemTrim = hv::rtrim(item, " ");
string ssid = itemTrim.substr(pos);
if (ssid == "--") {
continue;
}
string ssidUtf8Encoded = convert_escape_sequences(ssid);
ssidVec.emplace_back(sigLevel, ssid);
}
hlogi("scan end %d", ssidVec.size());
return 0;
}
罪魁祸首:
cpp
ssidVec.emplace_back(sigLevel, ssid);
也就是说:
-
ssidVec是Wifi类的成员变量 -
getWifiInfo()每调用一次 -
scanWifi()就往ssidVec里 继续 push
在整个 scanWifi() 函数里,没有任何地方清空 ssidVec。
导致:
SSID 重复
UUID(如果在 WifiInfo::toJson 里生成)也会重复/变化
每次"前端扫描"数量越来越多
NM 工具不会这样(它每次 scan 都是 fresh list)
修复点:
1.在 scanWifi() 一开始清空 ssidVec
cpp
int Wifi::scanWifi() {
ssidVec.clear(); // ← 每次扫描必须清空历史结果
2.nmcli -f SIGNAL,SSID d wifi list修改为:
cpp
nmcli -t -f SSID,BSSID,FREQ,SIGNAL dev wifi list
nmcli -f SIGNAL,SSID d wifi list会丢失BSSID/FREQ信息,导致没办法区分是同一个AP还是不同的AP
程序如下:
cpp
int Wifi::scanWifi() {
ssidVec.clear(); // ★ 必须清空
string ssids;
string scanCmd("nmcli -t -f SSID,BSSID,FREQ,SIGNAL dev wifi list");
if (!myPopen(scanCmd, ssids)) {
hloge("failed to scan ssid");
return -1;
}
stringstream ss(ssids);
string line;
while (getline(ss, line)) {
// 格式:SSID:BSSID:FREQ:SIGNAL
hv::StringList fields = hv::split(line, ':');
if (fields.size() < 4) continue;
string ssid = fields[0];
string bssid = fields[1];
string freq = fields[2];
string signalStr = fields[3];
if (ssid.empty() || ssid == "--") continue;
int sig = 0;
if (stringIsNumber(signalStr)) {
sig = stoi(signalStr);
}
int sigLevel = 0;
if (sig <= 20) sigLevel = 0;
else if (sig <= 40) sigLevel = 1;
else if (sig <= 60) sigLevel = 2;
else if (sig <= 80) sigLevel = 3;
else sigLevel = 4;
// ★ 关键:不要把 BSSID / FREQ 拼进 name
ssidVec.emplace_back(sigLevel, ssid /* 这里只放纯 SSID */);
}
hlogi("scan end %d", ssidVec.size());
return 0;
}
但是出来的名字还是有重复的,定位问题是因为:
只做了【解析】和【清空历史】,没有做【按 SSID 聚合】
-
nmcli 扫描结果本身就会返回:
-
同一个 SSID
-
多个 BSSID
-
多个频段(2.4G / 5G / 5G-2)
-
-
你现在是 "一条扫描结果 → 一条 WifiInfo"
所以看到的:
cpp
COMNOVA_Staff
COMNOVA_Staff
COMNOVA_Staff
解决问题
按SSID聚合后代码:
cs
int Wifi::scanWifi() {
ssidVec.clear();
string ssids;
string scanCmd("nmcli -t -f SSID,BSSID,FREQ,SIGNAL dev wifi list");
if (!myPopen(scanCmd, ssids)) {
hloge("failed to scan ssid");
return -1;
}
// 用 map 按 SSID 聚合,只保留信号最强的
unordered_map<string, int> bestSignal; // SSID -> sigLevel
stringstream ss(ssids);
string line;
while (getline(ss, line)) {
hv::StringList fields = hv::split(line, ':');
if (fields.size() < 4) continue;
string ssid = fields[0];
string signalStr = fields[3];
if (ssid.empty() || ssid == "--") continue;
int sig = 0;
if (stringIsNumber(signalStr)) {
sig = stoi(signalStr);
}
int sigLevel = 0;
if (sig <= 20) sigLevel = 0;
else if (sig <= 40) sigLevel = 1;
else if (sig <= 60) sigLevel = 2;
else if (sig <= 80) sigLevel = 3;
else sigLevel = 4;
auto it = bestSignal.find(ssid);
if (it == bestSignal.end() || sigLevel > it->second) {
bestSignal[ssid] = sigLevel;
}
}
// 转成 ssidVec
for (const auto& kv : bestSignal) {
ssidVec.emplace_back(kv.second, kv.first);
}
hlogi("scan end %d (after dedup)", ssidVec.size());
return 0;
}
问题二:信号不显示
发的json里并不包含信号强度:
cs
"auto_connect": true,
"name": "DIRECT-7t-客厅电视",
"password": "",
"setting": false,
"signal": 0,
"status": false
},
{
"auto_connect": true,
"name": "DIRECT-xx-客厅电视",
"password": "",
"setting": false,
"signal": 0,
"status": false
},
{
"auto_connect": true,
"name": "W51-Ch62-5G",
"password": "",
"setting": false,
"signal": 0,
"status": false
},

问题定位
先看一下wifi.h
cs
WifiInfo(int signal, const std::string &name)
: name(name), signal(signal) {
status = false;
setting = false;
autoConnect = true;
}
一开始以为是initWifiInfoCompareList覆盖掉了:
cpp
hv::Json Wifi::initWifiInfoCompareList(const string &wifiList, bool shouldConnect) {
string ssidOnline;
if (!shouldConnect) {
// 刷新时找到在线的wifi mac
ssidOnline = getOnlineWifiName();
}
bool isConnected = false;
// 根据wifi_list中的信息,更新搜索到的WifiInfo
hv::Json wifiListJson = hv::Json::parse(wifiList);
for (auto &listItem : wifiListJson) {
WifiList wList = WifiList::fromJson(listItem);
string ssidName = wList.getSsid();
for (auto &info : ssidVec) {
if (ssidName != info.getName()) {
continue;
}
string pwd = wList.getPassword();
bool autoConnect = wList.getAutoConnect();
info.setPassword(pwd);
info.setAutoConnect(autoConnect);
info.setSetting(true);
if (!shouldConnect) {
if (ssidOnline == info.getName()) {
info.setStatus(true);
}
} else {
if (!isConnected && autoConnect) {
setSsid(ssidName);
setPassword(pwd);
setAutoConnect(autoConnect);
hlogi("will auto connect %s", ssidName.c_str());
if (connect()) {
isConnected = true;
info.setStatus(true);
}
}
}
break;
}
}
hv::Json jsn = hv::Json::array();
for (const auto &item: ssidVec) {
jsn.emplace_back(item.toJson());
}
return jsn;
}
只更新了 :password,autoConnect,setting,status,没有任何地方再更新 signal。
所以添加代码验证:
cpp
int Wifi::getWifiInfo(hv::Json &resp, bool tryConnect) {
if (scanWifi() < 0) {
hloge("failed to scan wifi");
return -1;
}
for (auto &w : ssidVec) {
hlogi("[SCAN] %s signal=%d", w.getName().c_str(), w.getSignal());
}
// compare wifi list, connect if auto connect is true
string wifiList;
selectDeployCode(dbCodeToString(SysDeployCode::WIFI_LIST), wifiList);
hv::Json &&wifiJson = initWifiInfoCompareList(wifiList, tryConnect);
int ret = updateDatabaseWithEscape(dbCodeToString(SysDeployCode::WIFI_INFO), wifiJson);
if (ret < 0) {
hloge("failed to update wifi info");
return ret;
}
if (!tryConnect) {
resp["data"]["wifiInfo"] = wifiJson;
} else if (isConnected()) {
ret = updateDeployCode(dbCodeToString(SysDeployCode::ONLINE), "true");
if (ret < 0) {
hloge("failed to update wifi switch");
return ret;
}
}
for (auto &w : ssidVec) {
hlogi("[FINAL] %s signal=%d", w.getName().c_str(), w.getSignal());
}
return 0;
}
打印出来为:
cpp
1970-01-05 06:53:41.586 INFO [SCAN] DIRECT-7t-客厅电视 signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.586 INFO [SCAN] DIRECT-xx-客厅电视 signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.586 INFO [SCAN] W51-Ch62-5G signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.586 INFO [SCAN] 萱萱超棒 signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.586 INFO [SCAN] CCORE_WIRELESS_2.4G signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.586 INFO [SCAN] OrayBox-2.4G-4D28 signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.586 INFO [SCAN] COMNOVA_Staff signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.586 INFO [SCAN] QL480_98797 signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.586 INFO [SCAN] CCORE_WIRELESS signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.587 INFO [SCAN] HONOR 90 signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.587 INFO [SCAN] test1 signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.587 INFO [SCAN] Hyper_Link signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.587 INFO [SCAN] 3F-R11-Display signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.587 INFO [SCAN] W51-Ch62 signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.587 INFO [SCAN] DIRECT-SU-tcl_mt5879_cn signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 06:53:41.637 INFO [FINAL] DIRECT-7t-客厅电视 signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.637 INFO [FINAL] DIRECT-xx-客厅电视 signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.638 INFO [FINAL] W51-Ch62-5G signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.638 INFO [FINAL] 萱萱超棒 signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.638 INFO [FINAL] CCORE_WIRELESS_2.4G signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.638 INFO [FINAL] OrayBox-2.4G-4D28 signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.638 INFO [FINAL] COMNOVA_Staff signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.638 INFO [FINAL] QL480_98797 signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.638 INFO [FINAL] CCORE_WIRELESS signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.638 INFO [FINAL] HONOR 90 signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.638 INFO [FINAL] test1 signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.638 INFO [FINAL] Hyper_Link signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.638 INFO [FINAL] 3F-R11-Display signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.638 INFO [FINAL] W51-Ch62 signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 06:53:41.638 INFO [FINAL] DIRECT-SU-tcl_mt5879_cn signal=0 [wifi.cpp:72:getWifiInfo]
说明不是initWifiInfoCompareList的问题,是Scanwifi的问题,排查发现fields[3] 根本不是 SIGNAL。
现在用的是:
nmcli -t -f SSID,BSSID,FREQ,SIGNAL dev wifi list
-t模式的输出规则是
SSID:BSSID:FREQ:SIGNAL
nmcli 会对 SSID 里的冒号 : 做转义,显示为 \:
SIGNAL 根本不是 fields[3],而是 fields.back()
解决问题
修正scanwifi:
cpp
string ssid = fields[0];
string signalStr = fields[3];
为
cpp
string ssid = fields[0];
string signalStr = fields.back();
完整代码:
cpp
int Wifi::scanWifi() {
ssidVec.clear();
string ssids;
string scanCmd("nmcli -t -f SSID,BSSID,FREQ,SIGNAL dev wifi list");
if (!myPopen(scanCmd, ssids)) {
hloge("failed to scan ssid");
return -1;
}
// 用 map 按 SSID 聚合,只保留信号最强的
unordered_map<string, int> bestSignal; // SSID -> sigLevel
stringstream ss(ssids);
string line;
while (getline(ss, line)) {
hv::StringList fields = hv::split(line, ':');
if (fields.size() < 4) continue;
string ssid = fields[0];
string signalStr = fields.back();
if (ssid.empty() || ssid == "--") continue;
int sig = 0;
if (stringIsNumber(signalStr)) {
sig = stoi(signalStr);
}
int sigLevel = 0;
if (sig <= 20) sigLevel = 0;
else if (sig <= 40) sigLevel = 1;
else if (sig <= 60) sigLevel = 2;
else if (sig <= 80) sigLevel = 3;
else sigLevel = 4;
auto it = bestSignal.find(ssid);
if (it == bestSignal.end() || sigLevel > it->second) {
bestSignal[ssid] = sigLevel;
}
}
// 转成 ssidVec
for (const auto& kv : bestSignal) {
ssidVec.emplace_back(kv.second, kv.first);
}
hlogi("scan end %d (after dedup)", ssidVec.size());
return 0;
}
检查:
cpp
1970-01-05 07:01:48.869 INFO [SCAN] DIRECT-7t-客厅电视 signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.869 INFO [SCAN] DIRECT-SU-tcl_mt5879_cn signal=0 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.869 INFO [SCAN] W51-Ch62 signal=4 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.869 INFO [SCAN] CCORE_WIRELESS_2.4G signal=3 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.869 INFO [SCAN] OrayBox-2.4G-4D28 signal=2 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.869 INFO [SCAN] COMNOVA_Staff signal=3 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.869 INFO [SCAN] QL480_98797 signal=2 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.869 INFO [SCAN] CCORE_WIRELESS signal=2 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.869 INFO [SCAN] HONOR 90 signal=3 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.869 INFO [SCAN] test1 signal=2 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.869 INFO [SCAN] 3F-R11-Display signal=1 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.869 INFO [SCAN] W51-Ch62-5G signal=4 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.869 INFO [SCAN] 萱萱超棒 signal=4 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.869 INFO [SCAN] DIRECT-xx-客厅电视 signal=1 [wifi.cpp:50:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] DIRECT-7t-客厅电视 signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] DIRECT-SU-tcl_mt5879_cn signal=0 [wifi.cpp:72:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] W51-Ch62 signal=4 [wifi.cpp:72:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] CCORE_WIRELESS_2.4G signal=3 [wifi.cpp:72:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] OrayBox-2.4G-4D28 signal=2 [wifi.cpp:72:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] COMNOVA_Staff signal=3 [wifi.cpp:72:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] QL480_98797 signal=2 [wifi.cpp:72:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] CCORE_WIRELESS signal=2 [wifi.cpp:72:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] HONOR 90 signal=3 [wifi.cpp:72:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] test1 signal=2 [wifi.cpp:72:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] 3F-R11-Display signal=1 [wifi.cpp:72:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] W51-Ch62-5G signal=4 [wifi.cpp:72:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] 萱萱超棒 signal=4 [wifi.cpp:72:getWifiInfo]
1970-01-05 07:01:48.923 INFO [FINAL] DIRECT-xx-客厅电视 signal=1 [wifi.cpp:72:getWifiInfo]
现在就有wifi信号啦!
问题三:接口连上了WiFi但是报错500
输入密码,点确定,后台检查:
cpp
nmcli -t -f active,ssid dev wifi
no:W51-Ch62-5G
no:W51-Ch62
yes:萱萱超棒
但是前端显示500,连接失败。

问题定位
定位到前端调用的对应功能函数:
cpp
int Handler::wifiPwdSet(const HttpContextPtr& ctx) {
hv::Json req = ctx->json();
Wifi wifi(req["password"], req["auto_connect"], req["name"]);
int ret = wifi.requestConnect();
if (ret == -1 || !wifi.isConnected()) {
return response_status(ctx, HTTP_STATUS_INTERNAL_SERVER_ERROR, "wifi连接失败");
}
if (ret == -2) {
return response_status(ctx, HTTP_STATUS_INTERNAL_SERVER_ERROR, "failed to update database");
}
return response_status(ctx, HTTP_STATUS_OK, "success");
}
cpp
/**
* only invoked when wifi item with ssid/password is clicked in front UI
* @return 0 on success, while -1 on failure
*/
int Wifi::updateDatabaseOnConnect() {
if (updateWifiInfoOnConnect() < 0) {
hloge("failed to update wifi info");
return -1;
}
if (updateWifiListOnConnect() < 0) {
hloge("failed to update wifi list");
return -1;
}
return updateDeployCode(dbCodeToString(SysDeployCode::ONLINE), "true");
}
/**
* set wifi info status to be false when wifi disconnected
* @return 0 on success, while -1 on failure
*/
int Wifi::updateWifiInfoOnDisconnect() {
string info;
string dbInfoStr = dbCodeToString(SysDeployCode::WIFI_INFO);
selectDeployCode(dbInfoStr, info);
hv::Json wifiJson = hv::Json::parse(info);
for (auto &item: wifiJson) {
item["status"] = false;
}
return updateDatabaseWithEscape(dbInfoStr, wifiJson);
}
/**
* set auto_connect/password/setting/status when wifi connected
* @return 0 on success, while -1 on failure
*/
int Wifi::updateWifiInfoOnConnect() {
string wifiInfo;
string dbInfoStr = dbCodeToString(SysDeployCode::WIFI_INFO);
selectDeployCode(dbInfoStr, wifiInfo);
hv::Json wifiJson = hv::Json::parse(wifiInfo);
bool found = false;
for (auto &item: wifiJson) {
if (found) {
item["status"] = false;
continue;
}
string ssid = item["name"];
if (ssid == getSsid()) {
item["auto_connect"] = isAutoConnect();
item["password"] = getPassword();
item["setting"] = true;
item["status"] = true;
found = true;
}
}
return updateDatabaseWithEscape(dbInfoStr, wifiJson);
}
/**
* update wifiList when wifi connected
* @return 0 on success, while -1 on failure
*/
int Wifi::updateWifiListOnConnect() {
string wifiList;
string dbInfoStr = dbCodeToString(SysDeployCode::WIFI_LIST);
selectDeployCode(dbInfoStr, wifiList);
hv::Json listJson = hv::Json::parse(wifiList);
list<WifiList> objWifiList;
for (auto &item: listJson) {
WifiList obj = WifiList::fromJson(item);
objWifiList.push_back(obj);
}
string pwd = getPassword();
string onlineSsid = getSsid();
bool isAutoConn = isAutoConnect();
int i = 0;
for (auto it = objWifiList.begin(); it != objWifiList.end(); ++it) {
if (it->getSsid() == onlineSsid) {
it->setPassword(pwd);
it->setAutoConnect(isAutoConn);
objWifiList.splice(objWifiList.cbegin(), objWifiList, it);
break;
}
i++;
}
if (i == objWifiList.size()) {
objWifiList.emplace_front(pwd, ssid, isAutoConn);
}
listJson.clear();
for (auto &item: objWifiList) {
listJson.push_back(item.toJson());
}
return updateDatabaseWithEscape(dbInfoStr, listJson);
}
/**
* disconnect wifi
* @return true on success, while false on failure
*/
bool Wifi::disconnect() {
if (!isConnected()) {
return true;
}
string interface("wlan0");
string cmd = "nmcli d disconnect " + interface;
if (!mySystem(cmd)) {
hloge("failed to disconnect wifi");
return false;
}
return updateDeployCode(dbCodeToString(SysDeployCode::ONLINE), boolToString(false));
}
/**
* check wifi connected or not by /sys/class/net/mlan0/operstate
* @return true if content is up in the file, while false if down
*/
bool Wifi::isConnected() {
const std::string interfaceName = "wlan0";
std::ifstream file("/sys/class/net/" + interfaceName + "/operstate");
bool res = false;
if (file.is_open()) {
std::string state;
file >> state;
file.close();
if (state == "up") {
res = true;
}
}
hlogi("check wifi connected: %d", res);
return res;
}
解决问题
看代码立刻发现问题:网卡名没改过来
cpp
bool Wifi::isConnected() {
const std::string interfaceName = "wlP1p1s0"; //❗
std::ifstream file("/sys/class/net/" + interfaceName + "/operstate");
bool res = false;
if (file.is_open()) {
std::string state;
file >> state;
file.close();
if (state == "up") {
res = true;
}
}
hlogi("check wifi connected: %d", res);
return res;
}
但是改了还是有可能报500
猜想问题点:
1.在程序里,连接成功和后续状态/数据库更新失败被当成了一回事。
可能connet成功了,但updateDatabaseOnConnect某一步失败了。
如果是这样,要不解决updateDatabaseOnConnect的bug,要不连接成功了就返回0,数据库更新失败不返回。
2.可能wifi连接有延迟,HTTP 请求已经结束(500),NetworkManager 还在后台继续,几秒后 Wi-Fi 真正连上
看日志:
cpp
1970-01-05 07:11:33.650 INFO [106289-106289][127.0.0.1:58332][GET /networkmanage/wifiScan]=>[200 OK] [HttpServer.cpp:175:on_recv]
1970-01-05 07:11:38.222 INFO check wifi connected: 0 [wifi.cpp:395:isConnected]
1970-01-05 07:11:38.222 INFO [106289-106289][127.0.0.1:58352][POST /networkmanage/wifiPassSet]=>[500 Internal Server Error] [HttpServer.cpp:175:on_recv]
1970-01-05 07:11:46.973 INFO check wifi connected: 0 [wifi.cpp:395:isConnected]
1970-01-05 07:11:46.973 INFO [106289-106289][127.0.0.1:58336][POST /networkmanage/wifiPassSet]=>[500 Internal Server Error] [HttpServer.cpp:175:on_recv]
1970-01-05 07:11:53.834 INFO check wifi connected: 0 [wifi.cpp:395:isConnected]
1970-01-05 07:11:53.834 INFO [106289-106289][127.0.0.1:58334][POST /networkmanage/wifiPassSet]=>[500 Internal Server Error] [HttpServer.cpp:175:on_recv]
1970-01-05 07:12:07.128 INFO check wifi connected: 0 [wifi.cpp:395:isConnected]
1970-01-05 07:12:07.129 INFO [106289-106289][127.0.0.1:58366][POST /networkmanage/wifiPassSet]=>[500 Internal Server Error] [HttpServer.cpp:175:on_recv]
1970-01-05 07:12:13.744 INFO check wifi connected: 0 [wifi.cpp:395:isConnected]
1970-01-05 07:12:13.745 INFO [106289-106289][127.0.0.1:58356][POST /networkmanage/wifiPassSet]=>[500 Internal Server Error] [HttpServer.cpp:175:on_recv]
"check wifi connected: %d"来自:
cpp
bool Wifi::isConnected() {
const std::string interfaceName = "wlan0";
std::ifstream file("/sys/class/net/" + interfaceName + "/operstate");
bool res = false;
if (file.is_open()) {
std::string state;
file >> state;
file.close();
if (state == "up") {
res = true;
}
}
hlogi("check wifi connected: %d", res);
return res;
}
没有出现
failed to update wifi info
failed to update wifi list
所以500 不是 updateDatabaseOnConnect() 里抛出来的。
| 视角 | 含义 |
|---|---|
nmcli d wifi connect |
命令已下发,NetworkManager 接受 |
/sys/class/net/wlan0/operstate |
内核网卡是否 UP |
| IP 是否拿到 | DHCP 是否完成 |
| UI 感觉 | Wi-Fi 图标亮了 |
这些都不是同步发生,但是我检查用的指令nmcli d wifi connect 是异步的。
NetworkManager:
-
先关联 AP
-
再 WPA 握手
-
再 DHCP
-
最后内核接口才
UP
好的,知道原因了,是我查太早了。
现在有两个修改方案:
方案1.wifiPwdSet只判断是否下发成功
方案2.等待连接
最佳方案为方案1,为了尽量不影响逻辑,先尝试用方案2。
更新代码:
cpp
int Handler::wifiPwdSet(const HttpContextPtr& ctx) {
hv::Json req = ctx->json();
Wifi wifi(req["password"], req["auto_connect"], req["name"]);
int ret = wifi.requestConnect();
if (ret == -1) {
return response_status(ctx, HTTP_STATUS_INTERNAL_SERVER_ERROR, "wifi连接命令失败");
}
if (ret == -2) {
return response_status(ctx, HTTP_STATUS_INTERNAL_SERVER_ERROR, "failed to update database");
}
// 等待最多 2 次,每次 1 秒
const int retry = 2;
for (int i = 0; i < retry; ++i) {
if (Wifi::isConnected()) {
return response_status(ctx, HTTP_STATUS_OK, "success");
}
sleep(3);
}
// 两次都没连上,判定失败
return response_status(ctx, HTTP_STATUS_INTERNAL_SERVER_ERROR, "wifi连接失败");
}
完美解决!
问题四:硬编码问题
发现此问题的来源:
点击忘记网络,wifi依然连接,但界面上显示无wifi连接

问题定位
handler.cpp:
cpp
/**
* ignore wifi: disconnect it and delete it in the wifi_list
*/
int Handler::wifiIgnore(const HttpContextPtr &ctx) {
hv::Json req = ctx->json();
string ssidName = req["name"];
Wifi wifi;
if (wifi.getWifiInfoFromDb() < 0) {
return response_status(ctx, HTTP_STATUS_INTERNAL_SERVER_ERROR, "操作失败");
}
hv::Json resp;
if (wifi.ignore(ssidName, resp["data"]["wifiInfo"]) < 0) {
return response_status(ctx, HTTP_STATUS_INTERNAL_SERVER_ERROR, "操作失败");
}
resp["msg"] = "success";
resp["code"] = HTTP_STATUS_OK;
return ctx->sendJson(resp);
}
wifi.cpp:
cpp
int Wifi::ignore(const std::string &name, hv::Json &wifiJson) {
wifiJson = hv::Json::array();
for(auto &it : ssidVec) {
if (name == it.getName()) {
if (it.getStatus()) {
disconnect();
}
it.setAutoConnect(true);
it.setPassword("");
it.setSetting(false);
it.setStatus(false);
}
wifiJson.emplace_back(it.toJson());
}
updateDatabaseWithEscape(dbCodeToString(SysDeployCode::WIFI_INFO), wifiJson);
// 从wifi_list中删除此wifi
string wifiList;
selectDeployCode(dbCodeToString(SysDeployCode::WIFI_LIST), wifiList);
hv::Json listJson = hv::Json::parse(wifiList);
for (auto it = listJson.begin(); it != listJson.end(); ++it) {
WifiList item = WifiList::fromJson(*it);
if (item.getSsid() == name) {
listJson.erase(it);
break;
}
}
return updateDatabaseWithEscape(dbCodeToString(SysDeployCode::WIFI_LIST), listJson);
}
bool Wifi::disconnect() {
if (!isConnected()) {
return true;
}
string interface("wlan0"); // ❗
string cmd = "nmcli d disconnect " + interface;
if (!mySystem(cmd)) {
hloge("failed to disconnect wifi");
return false;
}
return updateDeployCode(dbCodeToString(SysDeployCode::ONLINE), boolToString(false));
}
????这里怎么又有一个网卡名要更改?
一搜有一堆硬编码:

解决方案:
可不可以程序初始化的时候获取wifi接口,后面把网卡名存在一个变量里,要用的地方就调用这个变量,外部不允许可以修改这个变量,当然肯定不用全局string
解决问题
直接贴代码:
wifi.h:
cpp
/**
* Wi-Fi runtime environment
* Initialized once at program startup
*/
class WifiEnv {
public:
// 程序启动时调用一次
static bool init();
// 只读获取 Wi-Fi 接口名
static const std::string& iface();
private:
WifiEnv() = delete;
static std::string wifi_iface_;
static constexpr const char* DEFAULT_WIFI_IFACE = "wlP1p1s0";
};
wifi.cpp:
cpp
std::string WifiEnv::wifi_iface_;
bool WifiEnv::init() {
std::string out;
std::string cmd =
"nmcli -t -f DEVICE,TYPE,STATE d | "
"awk -F: '$2==\"wifi\" && $3!=\"unavailable\" {print $1; exit}'";
if (myPopen(cmd, out)) {
out.erase(std::remove(out.begin(), out.end(), '\n'), out.end());
}
if (!out.empty()) {
wifi_iface_ = out;
hlogi("wifi interface detected: %s", wifi_iface_.c_str());
return true;
}
// fallback:使用默认接口名
wifi_iface_ = DEFAULT_WIFI_IFACE;
hloge("wifi interface detect failed, fallback to default: %s",
wifi_iface_.c_str());
return true;
}
const std::string& WifiEnv::iface() {
return wifi_iface_;
}
main.cpp:
cpp
#include "base/wifi.h"
.............
WifiEnv::init();
调用:
cpp
const std::string& interface = WifiEnv::iface();
if (interface.empty()) return false;