从 C++ 代码检查互联网连接
Checking internet connection from C++ code
在为遗留应用程序处理大型代码库时,每当我看到一段检查互联网连接是否处于活动状态的代码时,我大多看到函数的使用,例如:
InternetCheckConnection(L"http://www.google.com",FLAG_ICC_FORCE_CONNECTION,0)
//or
BOOL bConnected = IsNetworkAlive(&dwSens)
//or
InternetGetConnectedState(&dwReturnedFlag, 0)
//or some other functions
但是有一种非常非常简单的方法可以做到这一点,您不需要包含其他编写代码的头文件,即:
if (system("ping www.google.com"))
我的问题是,当我需要查看连接是否可用时,使用代码中的 ping
有什么缺点(如果有的话)?
假设 ping
不会在我的软件要 运行 的机器上被禁用。
system("ping www.google.com")
的缺点是双重的:
如果有人用自己的命令替换了系统 ping
命令,它可能会给您错误的结果 [并且如果调用 ping
的进程是 运行 额外的特权,它可以用该特权做一些事情 "interesting"]。这对任何 system
操作都是通用的。
您正在启动另一个进程,然后必须 运行 并在您得到答案之前关闭 [当然,或多或少会做与 InternetCheckConnection
相同的事情确实 - 查找名称,将其转换为 IP 地址,将数据包发送到该地址,等待响应,解释该响应,等等。
根据 Microsoft API 文档 InternetCheckConnection 已弃用。
[InternetCheckConnection is available for use in the operating systems specified in the Requirements section. It may be altered or unavailable in subsequent versions. Instead, use NetworkInformation.GetInternetConnectionProfile or the NLM Interfaces. ]
我们可以使用 INetworkListManager 界面来检查 windows 平台是否已连接互联网,而不是这个 API。
以下是 win32 代码库:
#include <iostream>
#include <ObjBase.h> // include the base COM header
#include <Netlistmgr.h>
// Instruct linker to link to the required COM libraries
#pragma comment(lib, "ole32.lib")
using namespace std;
enum class INTERNET_STATUS
{
CONNECTED,
DISCONNECTED,
CONNECTED_TO_LOCAL,
CONNECTION_ERROR
};
INTERNET_STATUS IsConnectedToInternet();
int main()
{
INTERNET_STATUS connectedStatus = INTERNET_STATUS::CONNECTION_ERROR;
connectedStatus = IsConnectedToInternet();
switch (connectedStatus)
{
case INTERNET_STATUS::CONNECTED:
cout << "Connected to the internet" << endl;
break;
case INTERNET_STATUS::DISCONNECTED:
cout << "Internet is not available" << endl;
break;
case INTERNET_STATUS::CONNECTED_TO_LOCAL:
cout << "Connected to the local network." << endl;
break;
case INTERNET_STATUS::CONNECTION_ERROR:
default:
cout << "Unknown error has been occurred." << endl;
break;
}
}
INTERNET_STATUS IsConnectedToInternet()
{
INTERNET_STATUS connectedStatus = INTERNET_STATUS::CONNECTION_ERROR;
HRESULT hr = S_FALSE;
try
{
hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
INetworkListManager* pNetworkListManager;
hr = CoCreateInstance(CLSID_NetworkListManager, NULL, CLSCTX_ALL, __uuidof(INetworkListManager), (LPVOID*)&pNetworkListManager);
if (SUCCEEDED(hr))
{
NLM_CONNECTIVITY nlmConnectivity = NLM_CONNECTIVITY::NLM_CONNECTIVITY_DISCONNECTED;
VARIANT_BOOL isConnected = VARIANT_FALSE;
hr = pNetworkListManager->get_IsConnectedToInternet(&isConnected);
if (SUCCEEDED(hr))
{
if (isConnected == VARIANT_TRUE)
connectedStatus = INTERNET_STATUS::CONNECTED;
else
connectedStatus = INTERNET_STATUS::DISCONNECTED;
}
if (isConnected == VARIANT_FALSE && SUCCEEDED(pNetworkListManager->GetConnectivity(&nlmConnectivity)))
{
if (nlmConnectivity & (NLM_CONNECTIVITY_IPV4_LOCALNETWORK | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_LOCALNETWORK | NLM_CONNECTIVITY_IPV6_SUBNET))
{
connectedStatus = INTERNET_STATUS::CONNECTED_TO_LOCAL;
}
}
pNetworkListManager->Release();
}
}
CoUninitialize();
}
catch (...)
{
connectedStatus = INTERNET_STATUS::CONNECTION_ERROR;
}
return connectedStatus;
}
如果您正在使用 boost
,您可以执行以下操作:
static bool has_internet(net::io_context& ioc) {
tcp::resolver resolver(boost::asio::make_strand(ioc));
boost::beast::error_code ec;
auto endpoints = resolver.resolve("google.com", "80", ec);
if (endpoints.empty() || ec.failed())
return false;
return true;
}
在为遗留应用程序处理大型代码库时,每当我看到一段检查互联网连接是否处于活动状态的代码时,我大多看到函数的使用,例如:
InternetCheckConnection(L"http://www.google.com",FLAG_ICC_FORCE_CONNECTION,0)
//or
BOOL bConnected = IsNetworkAlive(&dwSens)
//or
InternetGetConnectedState(&dwReturnedFlag, 0)
//or some other functions
但是有一种非常非常简单的方法可以做到这一点,您不需要包含其他编写代码的头文件,即:
if (system("ping www.google.com"))
我的问题是,当我需要查看连接是否可用时,使用代码中的 ping
有什么缺点(如果有的话)?
假设 ping
不会在我的软件要 运行 的机器上被禁用。
system("ping www.google.com")
的缺点是双重的:
如果有人用自己的命令替换了系统
ping
命令,它可能会给您错误的结果 [并且如果调用ping
的进程是 运行 额外的特权,它可以用该特权做一些事情 "interesting"]。这对任何system
操作都是通用的。您正在启动另一个进程,然后必须 运行 并在您得到答案之前关闭 [当然,或多或少会做与
InternetCheckConnection
相同的事情确实 - 查找名称,将其转换为 IP 地址,将数据包发送到该地址,等待响应,解释该响应,等等。
根据 Microsoft API 文档 InternetCheckConnection 已弃用。
[InternetCheckConnection is available for use in the operating systems specified in the Requirements section. It may be altered or unavailable in subsequent versions. Instead, use NetworkInformation.GetInternetConnectionProfile or the NLM Interfaces. ]
我们可以使用 INetworkListManager 界面来检查 windows 平台是否已连接互联网,而不是这个 API。
以下是 win32 代码库:
#include <iostream>
#include <ObjBase.h> // include the base COM header
#include <Netlistmgr.h>
// Instruct linker to link to the required COM libraries
#pragma comment(lib, "ole32.lib")
using namespace std;
enum class INTERNET_STATUS
{
CONNECTED,
DISCONNECTED,
CONNECTED_TO_LOCAL,
CONNECTION_ERROR
};
INTERNET_STATUS IsConnectedToInternet();
int main()
{
INTERNET_STATUS connectedStatus = INTERNET_STATUS::CONNECTION_ERROR;
connectedStatus = IsConnectedToInternet();
switch (connectedStatus)
{
case INTERNET_STATUS::CONNECTED:
cout << "Connected to the internet" << endl;
break;
case INTERNET_STATUS::DISCONNECTED:
cout << "Internet is not available" << endl;
break;
case INTERNET_STATUS::CONNECTED_TO_LOCAL:
cout << "Connected to the local network." << endl;
break;
case INTERNET_STATUS::CONNECTION_ERROR:
default:
cout << "Unknown error has been occurred." << endl;
break;
}
}
INTERNET_STATUS IsConnectedToInternet()
{
INTERNET_STATUS connectedStatus = INTERNET_STATUS::CONNECTION_ERROR;
HRESULT hr = S_FALSE;
try
{
hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
INetworkListManager* pNetworkListManager;
hr = CoCreateInstance(CLSID_NetworkListManager, NULL, CLSCTX_ALL, __uuidof(INetworkListManager), (LPVOID*)&pNetworkListManager);
if (SUCCEEDED(hr))
{
NLM_CONNECTIVITY nlmConnectivity = NLM_CONNECTIVITY::NLM_CONNECTIVITY_DISCONNECTED;
VARIANT_BOOL isConnected = VARIANT_FALSE;
hr = pNetworkListManager->get_IsConnectedToInternet(&isConnected);
if (SUCCEEDED(hr))
{
if (isConnected == VARIANT_TRUE)
connectedStatus = INTERNET_STATUS::CONNECTED;
else
connectedStatus = INTERNET_STATUS::DISCONNECTED;
}
if (isConnected == VARIANT_FALSE && SUCCEEDED(pNetworkListManager->GetConnectivity(&nlmConnectivity)))
{
if (nlmConnectivity & (NLM_CONNECTIVITY_IPV4_LOCALNETWORK | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_LOCALNETWORK | NLM_CONNECTIVITY_IPV6_SUBNET))
{
connectedStatus = INTERNET_STATUS::CONNECTED_TO_LOCAL;
}
}
pNetworkListManager->Release();
}
}
CoUninitialize();
}
catch (...)
{
connectedStatus = INTERNET_STATUS::CONNECTION_ERROR;
}
return connectedStatus;
}
如果您正在使用 boost
,您可以执行以下操作:
static bool has_internet(net::io_context& ioc) {
tcp::resolver resolver(boost::asio::make_strand(ioc));
boost::beast::error_code ec;
auto endpoints = resolver.resolve("google.com", "80", ec);
if (endpoints.empty() || ec.failed())
return false;
return true;
}