嵌入式linux系统中没有内置自动化程度高的管理程序,这个程序就完成根据有线插拔来判断是否启用无线的功能。
qtenetworkmanager.h
#ifndef QTENETWORKMANAGER_H
#define QTENETWORKMANAGER_H
#include <QObject>
#include <QTimer>
#include <QList>
#include "QTEDefine.h"
#include <qthread.h>
#include "QTEDefine.h"
class QTENetworkClearThread : public QThread
{
Q_OBJECT
public:
QTENetworkClearThread(QObject* parent = 0) : QThread(parent) {
}
signals:
void cleared();
void notcleared();
// QThread interface
protected:
void run();
};
class QTEDhcpThread : public QThread
{
Q_OBJECT
public:
QTEDhcpThread(QObject* parent = 0) : QThread(parent) {
}
void setnet(QString eth = "eth0") {net=eth;}
signals:
void passed(QString);
// QThread interface
protected:
void run();
private:
QString net;
};
// thread unsafe
class QTENetworkManager : public QObject
{
Q_OBJECT
public:
static QTENetworkManager *Instance(QObject* parent = 0);
QList<TWifi>& wifiList() { return m_wifiList; }
inline TWifi currentWifi(){ return m_curWifi; }
bool setCurrentWifi(QString bssid_mac, QString password = "");
void setRefresh(bool ref = true) { ref ? m_workTimer->start(5000) : m_workTimer->stop(); }
void setDHCP(bool bUse = false) { m_bUseDHCP = bUse; }
void configIPAddress(QString ip, QString mask, QString gw, QString dns);
QString currentNetName();
QTimer* workTimer() { return m_workTimer; }
void saveAddr(QString ip, QString mask, QString gw, QString dns);
void getAddr(QString& ip, QString& mask, QString& gw, QString& dns);
signals:
//没有配置就会发送这个信号
void sigScanning();
//断开连接的状态
void sigDisConnected();
//正在连接的状态
void sigConnecting();
//连接成功的状态
void sigConnected();
//Wifi列表更新 之上状态改变会影响list中wifi的标志位。
void sigRefreshed();
//Wifi状态改变
void sigStatusChanged(QString status);
//有线连接上
void sigLanConnected();
//有线断开
void sigLanDisConnected();
//网络线路连接上
void sigNetworkClear();
//网络线路断开
void sigNetworkNotClear();
private slots:
void refreshWifiList();
void refreshWifiStatus();
void checkLanConnection();
void DhcpPassed(QString netname);
void checkNetworkClear();
private:
explicit QTENetworkManager(QObject *parent = 0);
void readStatus();
void restoreWifi();
bool restartWifi();
void saveScript();
void config();
signals:
public slots:
private:
static QTENetworkManager* _instance;
QTimer* m_workTimer;
QList<TWifi> m_wifiList;
TWifi m_curWifi;
bool m_bUseDHCP;
QString m_netName;
QTEDhcpThread* m_thread;
QTENetworkClearThread* m_clearThread;
QString m_status;
};
#endif // QTENETWORKMANAGER_H
qtenetworkmanager.cpp
#include "QTENetworkManager.h"
#include "hnlinux.h"
#include "QTEDefine.h"
QTENetworkManager* QTENetworkManager::_instance = NULL;
QTENetworkManager *QTENetworkManager::Instance(QObject *parent)
{
if(_instance)
return _instance;
_instance = new QTENetworkManager(parent);
return _instance;
}
bool QTENetworkManager::setCurrentWifi(QString bssid_mac, QString password)
{
for(QList<TWifi>::Iterator it = m_wifiList.begin();
it != m_wifiList.end(); it++)
{
TWifi wifi = *it;
if(bssid_mac == wifi[ESSID_BSSID])
{
m_status = "";
m_curWifi = wifi;
m_curWifi[ESSID_PASS] = password;
break;
}
}
restoreWifi();
if(!restartWifi())
return false;
return true;
}
void QTENetworkManager::configIPAddress(QString ip, QString mask, QString gw, QString dns)
{
saveAddr(ip, mask, gw, dns);
saveScript();
config();
}
QString QTENetworkManager::currentNetName()
{
if("eth0" == m_netName)
return "Wired Lan";
if("wlan0" == m_netName)
if("COMPLETED" == m_status)
return m_curWifi[ESSID_NAME];
return "";
}
void QTENetworkManager::readStatus()
{
//从 status 中读取
char result[MAX_LEN];
char key[MAX_LEN]; //设置一个合适的长度,以存储每一行输出
char value[MAX_LEN]; //设置一个合适的长度,以存储每一行输出
bzero(result, MAX_LEN);
bzero(key, MAX_LEN);
bzero(value, MAX_LEN);
FILE *pp = popen("wpa_cli -iwlan0 status", "r"); //建立管道
if (!pp)
return;
while( fgets(result, sizeof(result), pp) != NULL)
{
sscanf(result, "%[^=]=%s", key, value);
//如果这里不用QString包含,会对比地址
if(QString("wpa_state") == QString(key)) {
m_curWifi[ESSID_STATUS] = value;
} else if(QString("bssid") == QString(key)) {
m_curWifi[ESSID_BSSID] = value;
} else if(QString("ssid") == QString(key)) {
m_curWifi[ESSID_NAME] = value;
}
}
pclose(pp);
return;
}
void QTENetworkManager::refreshWifiList()
{
static int scanid = 0;
if(scanid == 12)
scanid = 0, system("wpa_cli -iwlan0 scan");
scanid ++;
FILE *pp = popen("wpa_cli -iwlan0 scan_r", "r"); //建立管道
if (!pp)
return;
char cmdresult[MAX_LEN]; //设置一个合适的长度,以存储每一行输出
fgets(cmdresult, sizeof(cmdresult), pp) ; //""
char bssid[MAX_PATH];
char frequency[MAX_PATH];
char signal[MAX_PATH];
char flag[MAX_PATH];
char ssid[MAX_PATH];
m_wifiList.clear();
while( fgets(cmdresult, sizeof(cmdresult), pp) != NULL)
{
sscanf(cmdresult, "%s\t%s\t%s\t%s\t%s\n", bssid, frequency, signal, flag, ssid);
TWifi wifi;
wifi[ESSID_NAME] = ssid;
if( strstr(flag, "WPA"))
wifi[ESSID_TYPE] = "WPA";
else
wifi[ESSID_TYPE] = "WEP";
if(strstr(flag, "WPA") || strstr(flag, "WEP"))
wifi[ESSID_ENCRYP] = "YES";
else
wifi[ESSID_ENCRYP] = "NO";
wifi[ESSID_PASS] = "";
wifi[ESSID_BSSID] = bssid;
wifi[ESSID_FREQ] = frequency;
wifi[ESSID_SIGNAL] = signal;
wifi[ESSID_FLAG] = flag;
if(wifi[ESSID_BSSID] == m_curWifi[ESSID_BSSID])
wifi[ESSID_STATUS] = m_curWifi[ESSID_STATUS];
else
wifi[ESSID_STATUS] = "";
m_wifiList.push_back(wifi);
//pline() << ssid << frequency << signal << flag << bssid << wifi[ESSID_STATUS];
}
//pline() << m_wifiList.size();
pclose(pp); //关闭管道
emit sigRefreshed();
}
void QTENetworkManager::refreshWifiStatus()
{
readStatus();
if(m_status == m_curWifi[ESSID_STATUS])
return;
pline() << m_curWifi[ESSID_BSSID] << m_curWifi[ESSID_NAME] << m_curWifi[ESSID_STATUS];
m_status = m_curWifi[ESSID_STATUS];
emit sigStatusChanged(m_status);
if("COMPLETED" == m_status)
emit sigConnected();
else if("SCANNING" == m_status)
emit sigScanning();
else if("ASSOCIATING" == m_status)
emit sigConnecting();
else if("INACTIVE" == m_status)
emit sigDisConnected();
else if("4WAY_HANDSHAKE" == m_status)
emit sigDisConnected();
else if("DISCONNECTED" == m_status)
emit sigDisConnected();
}
void QTENetworkManager::checkLanConnection()
{
char cmdbuf[MAX_PATH];
char cmdresult[MAX_PATH]; //设置一个合适的长度,以存储每一行输出
bzero(cmdbuf, MAX_PATH);
bzero(cmdresult, MAX_PATH);
sprintf(cmdbuf, "cat /sys/class/net/eth0/carrier");
FILE *pp = popen(cmdbuf, "r"); //建立管道
fgets(cmdresult, sizeof(cmdresult), pp); //""
pclose(pp);
QString netName = m_netName;
if(strstr(cmdresult, "0"))
m_netName = "wlan0";
else
m_netName = "eth0";
if(netName != m_netName)
{
config();
if("wlan0" == m_netName)
emit sigLanDisConnected();
else
emit sigLanConnected();
}
return;
}
void QTENetworkManager::DhcpPassed(QString netname)
{
int sockfd;
struct ifreq ifr;
struct sockaddr_in sin;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror("socket");
return;
}
strncpy(ifr.ifr_name, netname.toAscii().data(), IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ - 1] = 0;
//ip
if(ioctl(sockfd, SIOCGIFADDR, &ifr) <0)
perror("ioctl");
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
QString ip = QString(inet_ntoa(sin.sin_addr));
//mask
if (ioctl(sockfd, SIOCGIFNETMASK, &ifr) < 0)
perror("ioctl");
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
QString mask = QString(inet_ntoa(sin.sin_addr));
//mac
if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0)
perror("ioctl");
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
QString mac = QString(inet_ntoa(sin.sin_addr));
close(sockfd);
//gw
FILE *fp;
char buf[MAX_PATH];
char gateway[MAX_PATH];
bzero(buf, MAX_PATH);
bzero(gateway, MAX_PATH);
fp = popen("ip route", "r");
while(fgets(buf, sizeof(buf), fp) != NULL)
{
if(strstr(buf, "default via"))
{
sscanf(buf, "%*s%*s%s", gateway);
break;
}
}
pclose(fp);
QString gw = gateway;
//dns
QFile file("/etc/resolv.conf");
file.open(QFile::ReadOnly);
QByteArray nameserver = file.readLine();
nameserver[nameserver.size()-1] = '\0';
QList<QByteArray> namelist = nameserver.split(' ');
QString dns = namelist.size() > 1 ? namelist[1] : gw;
file.close();
//pt
pline() << netname << ip << mask << gw << dns;
saveAddr(ip, mask, gw, dns);
saveScript();
}
void QTENetworkManager::checkNetworkClear()
{
return;
m_clearThread->start();
}
QTENetworkManager::QTENetworkManager(QObject *parent) :
QObject(parent)
{
m_bUseDHCP = false;
m_clearThread = new QTENetworkClearThread(this);
connect(m_clearThread, SIGNAL(cleared()), this, SIGNAL(sigNetworkClear()));
connect(m_clearThread, SIGNAL(notcleared()), this, SIGNAL(sigNetworkNotClear()));
m_thread = new QTEDhcpThread(this);
connect(m_thread, SIGNAL(passed(QString)), this, SLOT(DhcpPassed(QString)));
//检查网线
//搜索热点
//刷新连接状态
m_workTimer = new QTimer(this);
m_workTimer->setSingleShot(false);
connect(m_workTimer, SIGNAL(timeout()), this, SLOT(refreshWifiList()));
connect(m_workTimer, SIGNAL(timeout()), this, SLOT(refreshWifiStatus()));
connect(m_workTimer, SIGNAL(timeout()), this, SLOT(checkLanConnection()));
connect(m_workTimer, SIGNAL(timeout()), this, SLOT(checkNetworkClear()));
#ifdef __MIPS_LINUX__
m_workTimer->start(5000);
//更新一次,以后一直调用scan_r 5-6s
system("wpa_cli -iwlan0 scan");
#endif
}
void QTENetworkManager::restoreWifi()
{
QString name = m_curWifi[ESSID_NAME];
QString password = m_curWifi[ESSID_PASS];
QString encryt = m_curWifi[ESSID_ENCRYP];
QString type = m_curWifi[ESSID_TYPE];
char cmdbuf[MAX_PATH];
char cmdresult[MAX_PATH];
FILE* fp=fopen("/etc/wpa_supplicant.conf", "wb");
fprintf(fp, "ctrl_interface=/var/run/wpa_supplicant\nctrl_interface_group=0\nap_scan=1\n\n");
if("NO" == encryt)
{
pline() << "None Encryption";
fprintf(fp, "network={\n\tssid=%s\n\tkey_mgmt=NONE\n\tpriority=5\n}\n", name.toAscii().data());
}
else if("WEP" == type)
{
pline() << "WEP Encryption";
fprintf(fp, "network={\n\tssid=\"%s\"\n\tkey_mgmt=NONE\n\twep_key0=%s\n\twep_tx_keyidx=0\n\tpriority=5\n\tauth_alg=SHARED\n}\n",
name.toAscii().data(), password.toAscii().data());
}
else if("WPA" == type)
{
pline() << "WPA Encryption";
bzero(cmdbuf, MAX_PATH);
bzero(cmdresult, MAX_PATH);
#if 0
sprintf(cmdbuf, "wpa_passphrase %s %s | awk 'NR==4{print $1}'", name.toAscii().data(), wifiPassword.toAscii().data());
FILE *pp = popen(cmdbuf, "r"); //建立管道
fgets(cmdresult, sizeof(cmdresult), pp) ; //""
pclose(pp);
fprintf(fp, "network={\n\tssid=\"%s\"\n\tkey_mgmt=WPA-PSK\n\tgroup=TKIP\n\tpairwise=CCMP\n\tproto=WPA\n\t#psk=\"%s\"\n\t%s\tpriority=5\n}\n",
name, wifiPassword, cmdresult);
#else
sprintf(cmdbuf, "wpa_passphrase %s %s", name.toAscii().data(), password.toAscii().data());
FILE *pp = popen(cmdbuf, "r"); //建立管道
while(fgets(cmdresult, sizeof(cmdresult), pp)) //""
{
fputs(cmdresult, fp);
}
pclose(pp);
#endif
}
fclose(fp);
}
bool QTENetworkManager::restartWifi()
{
char cmdbuf[MAX_PATH];
char cmdresult[MAX_PATH]; //设置一个合适的长度,以存储每一行输出
bzero(cmdbuf, MAX_PATH);
bzero(cmdresult, MAX_PATH);
sprintf(cmdbuf, "wpa_cli -iwlan0 reconf");
FILE *pp = popen(cmdbuf, "r"); //建立管道
fgets(cmdresult, sizeof(cmdresult), pp); //""
pclose(pp);
if(strstr(cmdresult, "FAIL"))
return false;
return true;
}
void QTENetworkManager::saveScript()
{
QString ip, mask, gw, dns;
getAddr(ip, mask, gw, dns);
QFile script("./net.sh");
script.open(QFile::WriteOnly);
char cmdbuf[MAX_PATH];
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "#!/bin/sh\n\n");
script.write(cmdbuf);
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "ifconfig eth0 %s netmask %s up\n",
ip.toAscii().data(),
mask.toAscii().data());
script.write(cmdbuf);
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "ifconfig wlan0 %s netmask %s up\n",
ip.toAscii().data(),
mask.toAscii().data());
script.write(cmdbuf);
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "route add default gw %s netmask 0.0.0.0 dev eth0\n",
gw.toAscii().data());
script.write(cmdbuf);
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "route add default gw %s netmask 0.0.0.0 dev wlan0\n",
gw.toAscii().data());
script.write(cmdbuf);
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "echo nameserver %s > /etc/resolv.conf\n", dns.toAscii().data());
script.write(cmdbuf);
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "wpa_supplicant -B -Dwext -iwlan0 -c/etc/wpa_supplicant.conf\n");
script.write(cmdbuf);
script.close();
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "chmod +x ./net.sh");
system(cmdbuf);
}
void QTENetworkManager::config()
{
char cmdbuf[MAX_PATH];
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "ip route | awk '{print $1}' | while read line; do ip route del $line; done");
system(cmdbuf);
//system("route");
if(m_bUseDHCP)
{
m_thread->setnet(m_netName);
m_thread->start();
return;
}
QString ip, mask, gw, dns;
getAddr(ip, mask, gw, dns);
pline() << m_netName << ip << mask << gw << dns;
// add .0 route
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "ifconfig %s 0.0.0.0 up", m_netName.toAscii().data());
system(cmdbuf);
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "ifconfig %s %s netmask %s",
m_netName.toAscii().data(),
ip.toAscii().data(),
mask.toAscii().data());
system(cmdbuf);
QStringList sl = gw.split(".");
if(sl.size() < 3) { sl.clear(); sl << "0" << "0" << "0" << "0";}
QString net = QString("%1.%2.%3.0").arg(sl[0]).arg(sl[1]).arg(sl[2]);
#if 0
//dhcp后 ifconfig up 引发了添加这条route
//ifconfig 0.0.0.0 也能引发添加这条route
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "route add -net %s netmask %s dev %s",
net.toAscii().data(),
mask.toAscii().data(),
m_netName.toAscii().data());
system(cmdbuf);
#endif
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "route add default gw %s netmask 0.0.0.0 dev %s",
gw.toAscii().data(),
m_netName.toAscii().data());
system(cmdbuf);
//system("route");
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "echo nameserver %s > /etc/resolv.conf", dns.toAscii().data());
system(cmdbuf);
}
void QTENetworkManager::saveAddr(QString ip, QString mask, QString gw, QString dns)
{
QSettings netSet;
netSet.setValue("/Network/IP", ip);
netSet.setValue("/Network/Gateway", gw);
netSet.setValue("/Network/Mask", mask);
netSet.setValue("/Network/DNS", dns);
netSet.sync();
}
void QTENetworkManager::getAddr(QString &ip, QString &mask, QString &gw, QString &dns)
{
QSettings netSet;
ip = netSet.value("/Network/IP").toString();
mask = netSet.value("/Network/Mask").toString();
gw = netSet.value("/Network/Gateway").toString();
dns = netSet.value("/Network/DNS").toString();
}
void QTEDhcpThread::run()
{
char cmdbuf[MAX_PATH];
bzero(cmdbuf, MAX_PATH);
sprintf(cmdbuf, "udhcpc -i %s", net.toAscii().data());
system(cmdbuf);
emit passed(net);
}
void QTENetworkClearThread::run()
{
static bool _bclear = false;
bool bclear = false;
char cmdbuf[MAX_PATH];
char cmdresult[MAX_PATH]; //设置一个合适的长度,以存储每一行输出
bzero(cmdbuf, MAX_PATH);
bzero(cmdresult, MAX_PATH);
sprintf(cmdbuf, "ping 222.175.114.244 -w 2 -c 1");
FILE *pp = popen(cmdbuf, "r"); //建立管道
while(fgets(cmdresult, sizeof(cmdresult), pp))
{
if(strstr(cmdresult, "1 packets transmitted, 1 packets received, 0% packet loss"))
bclear = true;
break;
}
pclose(pp);
if(_bclear != bclear)
{
if(bclear)
emit cleared();
else
emit notcleared();
_bclear = bclear;
}
return;
}
离线
又学到一招, 用 popen 可以启动一个进程,并获取进程的输出数据:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>int main(int argc, char *argv[])
{
FILE *stream;
char *line = NULL;
size_t len = 0;
ssize_t nread;if (argc != 2) {
fprintf(stderr, "Usage: %s <file>\n", argv[0]);
exit(EXIT_FAILURE);
}stream = popen("ls / -l", "r");
if (stream == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}while ((nread = getline(&line, &len, stream)) != -1)
{
// printf("Retrieved line of length %zu:\n", nread);
fwrite(line, nread, 1, stdout);
}free(line);
//fclose(stream);
pclose(stream);
exit(EXIT_SUCCESS);
}
这是程序输出:
lilo@ubuntu:/tmp$ ./main main.c
total 164
drwxr-xr-x 4 root root 4096 Jul 13 08:05 bak.disk5.bak
drwxr-xr-x 2 root root 4096 Jul 1 2017 bin
drwxr-xr-x 3 root root 4096 May 17 2017 boot
drwxrwxr-x 2 root root 4096 Mar 27 2016 cdrom
drwxr-xr-x 16 root root 4460 Dec 8 11:30 dev
drwxr-xr-x 147 root root 12288 Nov 28 10:57 etc
drwxr-xr-x 3 root root 4096 Mar 27 2016 home
lrwxrwxrwx 1 root root 32 May 16 2017 initrd.img -> boot/initrd.img-4.2.0-42-generic
lrwxrwxrwx 1 root root 32 Mar 27 2016 initrd.img.old -> boot/initrd.img-4.2.0-27-generic
drwxr-xr-x 24 root root 4096 May 16 2017 lib
drwxr-xr-x 2 root root 4096 Apr 23 2017 lib64
drwx------ 2 root root 16384 Mar 27 2016 lost+found
drwxr-xr-x 4 root root 4096 Apr 21 2017 media
drwxr-xr-x 5 root root 4096 Nov 19 16:02 mnt
dr-xr-xr-x 273 root root 0 Nov 23 11:18 proc
drwx------ 7 root root 4096 Jun 22 15:26 root
drwxr-xr-x 27 root root 960 Nov 23 11:48 run
drwxr-xr-x 2 root root 12288 Jul 11 11:32 sbin
drwxr-xr-x 2 root root 4096 Feb 18 2016 srv
dr-xr-xr-x 13 root root 0 Nov 23 11:18 sys
drwxrwxrwx 2 root root 4096 May 16 2017 tftpboot
drwxrwxrwt 6 root root 32768 Dec 11 09:39 tmp
drwxr-xr-x 14 root root 4096 Jul 11 09:22 usr
drwxr-xr-x 14 root root 4096 May 25 2018 var
lrwxrwxrwx 1 root root 29 May 16 2017 vmlinuz -> boot/vmlinuz-4.2.0-42-generic
lrwxrwxrwx 1 root root 29 Mar 27 2016 vmlinuz.old -> boot/vmlinuz-4.2.0-27-generic
离线
二楼的代码 通过 FILE *pp = popen("wpa_cli -iwlan0 scan_r", "r"); //建立管道 调用 wpa_cli 命令扫描附近的wifi热点,然后通过管道读出数据,分析得到 wifi 热点和信号强度, 以前我怎么没想到呢, 还是得多看看别人的代码。
离线
https://github.com/stevenhoneyman/wpa_gui/tree/master/wpa_supplicant-2.4/wpa_supplicant/wpa_gui-qt4
有人直接把 wpa_supplicant 怼到 Qt上去了.
离线
wpa_gui这里有界面: https://w1.fi/wpa_supplicant/wpa_gui.html
离线
void QTENetworkManager::checkLanConnection()
{
char cmdbuf[MAX_PATH];
char cmdresult[MAX_PATH]; //设置一个合适的长度,以存储每一行输出
bzero(cmdbuf, MAX_PATH);
bzero(cmdresult, MAX_PATH);
sprintf(cmdbuf, "cat /sys/class/net/eth0/carrier");
这种方法检测网络是否连接成功, 学到了!
离线