想实现一个判断当前系统有没有外网的方法,想到了两种思路:
1)实现一个ICMP协议。但是这个需要root权限才能运行。可以参考:https://cloud.tencent.com/developer/article/1996958
2)通过ping指令,解析ping的结果来判断有没有网。
0)命令:system("ping 192.168.1.21 -c 2 > PingTempTest.txt"); // -c 2 表示ping两次。
1)再去解析PingTempTest.txt中的内容。
3)实际使用时由于ping是耗时操作,为了不阻塞主线程,开了一个子线程去调用ping。
4)注意:如果系统是中文版本,可能ping运行的结果格式不一致。将无法使用下面的解析方法。
5)编译时需要指定C++14,和链接线程库。
/*
* @author:xcywt
* @date:2022-03-30
* @contact me: https://www.cnblogs.com/xcywt/
*/
#ifndef __DDR_CHECKFOREXTRANET_H__
#define __DDR_CHECKFOREXTRANET_H__
#include <string>
namespace DDRSys
{
/*
检测有没有外网的。原理就是:尝试ping某个ip,然后解析ping的结果。
每次创建一个对象会开辟一个线程。在线程中循环ping。
可以通过 GetNetState 取得结果。
测试系统:ubuntu16.04
用法:
void test_20220330()
{
DDRSys::CheckForExtranet check;
check.SetPingIntervals(10);
//check.SetPingIp("114.114.114.114");
//check.SetPingIp("114.114.114.11");
//check.SetPingIp("8.8.8.8");
//check.SetPingIp("8.8.8.7");
check.SetPingIp("192.168.1.21");
int nnn = 0;
while (1)
{
nnn++;
//printf("test_20220330() nnn:%d State:%d\n", nnn, check.GetNetState());
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
if (nnn > 100)
break;
}
}
编译时需要指定C++14,和链接线程库。
g++ main.cpp CheckForExtranet.cpp -std=c++14 -lpthread
*/
class CheckForExtranet
{
public:
CheckForExtranet();
~CheckForExtranet();
// 设置需要ping的ip,一般指定 8.8.8.8 或者 114.114.114.114
void SetPingIp(std::string ip);
// 设置间隔时间。单位为秒。设置为10,表示每隔10秒尝试ping一次
void SetPingIntervals(int sec);
// -1:表示无效值 0:没网 1:有网
int GetNetState();
private:
class IMPL;
IMPL *m_pImp = nullptr;
};
}
#endif // __DDR_CHECKFOREXTRANET_H__
#include "CheckForExtranet.h"
#include <thread>
#include <mutex>
#include <fstream>
#include <vector>
namespace DDRSys
{
std::vector<std::string> split(const std::string &text, char sep)
{
std::vector<std::string> tokens;
std::size_t start = 0, end = 0;
while ((end = text.find(sep, start)) != std::string::npos) {
if (end != start) {
tokens.emplace_back(text.substr(start, end - start));
}
start = end + 1;
}
if (end != start) {
tokens.emplace_back(text.substr(start));
}
return tokens;
}
class CheckForExtranet::IMPL
{
public:
IMPL()
{
m_subThread = std::thread(subThread, (void*)this);
}
~IMPL()
{
printf("[%s] CheckForExtranet::IMPL::~IMPL() +++ \n", GetLogPrev().c_str());
if (1)
{
std::lock_guard<std::mutex> lll(m_mutex);
m_bQuit = true;
}
if (m_subThread.joinable())
{
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
m_subThread.join();
}
printf("[%s] CheckForExtranet::IMPL::~IMPL() --- \n", GetLogPrev().c_str());
}
std::string GetLogPrev()
{
return "ExtranetLog";
//return DDRSys::GetCurTimeStamp_MilSec(); // 这个函数返回当时时间戳的
}
void SetPingIp(std::string ip)
{
std::lock_guard<std::mutex> lll(m_mutex);
m_strPingIp = ip;
}
void SetPingIntervals(int sec)
{
std::lock_guard<std::mutex> lll(m_mutex);
m_Intervals = sec;
}
int GetNetState()
{
std::lock_guard<std::mutex> lll(m_mutex);
auto curr = m_nState;
return curr;
}
void _myLoop()
{
printf("[%s] CheckForExtranet::IMPL::_myLoop() +++ \n", GetLogPrev().c_str());
const int waitTime = 500;
int waitCount = -1;
while (1)
{
int Intervals = 0;
bool bQuit = false;
if (1)
{
std::lock_guard<std::mutex> lll(m_mutex);
bQuit = m_bQuit;
Intervals = m_Intervals;
}
if (bQuit)
{
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(waitTime));
if ((waitCount > (m_Intervals * 1000) / waitTime) || (waitCount < 0))
{
waitCount = 0;
Ping();
}
waitCount++;
}
printf("[%s] CheckForExtranet::IMPL::_myLoop() --- \n", GetLogPrev().c_str());
}
static void subThread(void *param)
{
if (param)
{
auto *pThis = (CheckForExtranet::IMPL*)param;
pThis->_myLoop();
}
}
void Ping()
{
std::string strip = "";
if (1)
{
std::lock_guard<std::mutex> lll(m_mutex);
strip = m_strPingIp;
}
std::string fileNameTemp("PingTempTest");
fileNameTemp += ".txt";
std::string cmd("ping ");
cmd += strip;
cmd += " -c 2 > ";
cmd += fileNameTemp;
printf("[%s] Start ping:%s cmd:[%s] ++++ \n", GetLogPrev().c_str(),strip.c_str(), cmd.c_str());
system(cmd.c_str());
// cmd eg:ping 192.168.1.21 -c 2 > PingTempTest.txt
// 这里是解析上面的结果。如果系统是中文版本,可能ping运行的结果格式不一致。将无法使用下面的解析方法。
int state = -1;
std::vector<std::string> vecTTT;
std::ifstream in(fileNameTemp.c_str());
if (in.is_open())
{
std::string s;
while (getline(in, s))
{
vecTTT.push_back(s);
}
in.close();
}
for (auto item : vecTTT)
{
if ((int)item.find("packet loss") > 0)
{
// 2 packets transmitted, 0 received, 100% packet loss, time 1001ms
auto vec = split(item, ','); // 这个函数是分隔用的。根据逗号分隔,结果放在vec中。
for (auto ii : vec)
{
if ((int)ii.find("packet loss") > 0)
{
int index = ii.find("%");
std::string str;
str.assign(ii.begin(), ii.begin() + index);
int packetLoss = std::atoi(str.c_str());
if (packetLoss >= 80)
state = 0; // 丢失率大于80%就认为是没网了
else
state = 1;
printf("[%s] ReadInfo:%s packetLoss:%d state:%d\n", GetLogPrev().c_str(), ii.c_str(), packetLoss, state);
break;
}
}
break;
}
}
/*
dadao@dadao:~$ ping 8.8.8.8 -c 2
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=116 time=48.8 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=116 time=50.3 ms
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 48.893/49.609/50.326/0.750 ms
dadao@dadao:~$ ping 8.8.8.82 -c 2
PING 8.8.8.82 (8.8.8.82) 56(84) bytes of data.
--- 8.8.8.82 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1001ms
dadao@dadao:~$
*/
if (1)
{
std::lock_guard<std::mutex> lll(m_mutex);
m_nState = state;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
printf("[%s] End ping:%s state:%d ---- \n", GetLogPrev().c_str(), strip.c_str(), state);
}
private:
std::thread m_subThread;
std::mutex m_mutex;
bool m_bQuit = false;
int m_nState = -1; // // -1表示结果无意义 0表示没网 1表示有网
std::string m_strPingIp = "8.8.8.8";
int m_Intervals = 10;
};
CheckForExtranet::CheckForExtranet()
{
m_pImp = new CheckForExtranet::IMPL();
}
CheckForExtranet::~CheckForExtranet()
{
if (m_pImp)
{
m_pImp->~IMPL();
m_pImp = nullptr;
}
}
void CheckForExtranet::SetPingIp(std::string ip)
{
if (m_pImp)
{
m_pImp->SetPingIp(ip);
}
}
void CheckForExtranet::SetPingIntervals(int sec)
{
if (m_pImp)
{
m_pImp->SetPingIntervals(sec);
}
}
int CheckForExtranet::GetNetState()
{
if (m_pImp)
{
return m_pImp->GetNetState();
}
return -1;
}
}
dadao@dadao:~/workspace/test/PIng$ ./a.out
ExtranetLog CheckForExtranet::IMPL::_myLoop() +++
ExtranetLog Start ping:192.168.1.21 cmd:ping 192.168.1.21 -c 2 > PingTempTest.txt ++++
ExtranetLog ReadInfo: 0% packet loss packetLoss:0 state:1
ExtranetLog End ping:192.168.1.21 state:1 ----
ExtranetLog Start ping:192.168.1.21 cmd:ping 192.168.1.21 -c 2 > PingTempTest.txt ++++
ExtranetLog ReadInfo: 0% packet loss packetLoss:0 state:1
ExtranetLog End ping:192.168.1.21 state:1 ----