想实现一个判断当前系统有没有外网的方法,想到了两种思路:
1)实现一个ICMP协议。但是这个需要root权限才能运行。可以参考:https://www.cnblogs.com/xcywt/p/16070814.html
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 ----