Windows10 c++获取网卡信息(ipv4,子网掩码,网关,mac地址)
关于
本文样式环境: win10 + vs2017 + c++11
1.说明
算是踩坑吧,先前一直认为一块网卡只能有一个IP。 今天发现结构体中,定义了相关结构: 一块网卡可以用多个IP。
2.连接库和头文件
- 2.1 头文件
#include <WinSock2.h>
#include <Iphlpapi.h>
- 2.2 库
Iphlpapi.lib
3.封装类
自己做了个封装,以后用,直接就它了。
- 3.1 头文件 源码
#pragma once
#include <string>
#include <list>
#if defined(_WIN32) || defined(_WIN64)
#ifndef os_is_win
#define os_is_win
#endif // !os_is_win
#elif defined(__linux__) || defined(_linux_) || defined(__unix) || defined(_unix_) || defined(_APPLE_)
#ifndef os_is_linux
#define os_is_linux
#endif // !os_is_linux
#endif// ! defined(_WIN32) || defined(_WIN64)
#if defined(os_is_win)
#ifndef _net_api_export_
#define _net_api_export_ __declspec(dllexport)
#else
#define _net_api_export_ __declspec(dllimport)
#endif // !#ifndef _net_api_export_
#elif defined(os_is_linux)
#ifndef _net_api_export_
#define _net_api_export_ __attribute__((visibility ("default")))
#endif // !_net_api_export_
#endif //! defined(os_is_win)
namespace lib_net
{
/**
* @brief: ip information
*/
struct ip_info_
{
std::string _inet4;
std::string _inet6;
std::string _subnet_mask;
std::string _gate;
void zero()
{
_inet4 = { "" };
_inet6 = { "" };
_subnet_mask = { "" };
_gate = { "" };
}
ip_info_()
{
zero();
}
};
using ip_info = ip_info_;
using ip_list = std::list< ip_info>;
/**
* @brief: the information of adapter
*/
struct net_adapter_info_
{
#ifdef os_is_win
int _index;
#endif //! os_is_win
std::string _name;
std::string _description;
std::string _dev_type;
std::string _mac;
ip_list _ip;
int _ip_size;
void zero()
{
#ifdef os_is_win
_index = 0;
#endif //! os_is_win
_name = { "" };
_description = { "" };
_dev_type = { "" };
_mac = { "" };
_ip.clear();
_ip_size = 0;
}
net_adapter_info_()
{
zero();
}
};
// to rename the type
using net_ada_info = net_adapter_info_;
// maybe, this machine has greater than 1 adapter
using net_ada_list = std::list<net_ada_info>;
//----------------------------------------------------------------------------------------
/**
* @brief: you could get the adapter information through this class on windows, linux and osx
*/
class _net_api_export_ net_adapter_helper
{
public:
//----------------------------------------------------------------------------------------
static net_adapter_helper& get_instance();
/**
* @brief: 获取Windows网卡信息
*/
net_ada_list get_info_win();
private:
template<typename ... Args>
static std::string str_format(const std::string &format, Args ... args)
{
auto size_buf = std::snprintf(nullptr, 0, format.c_str(), args ...) + 1;
std::unique_ptr<char[]> buf(new(std::nothrow) char[size_buf]);
if (!buf)
return std::string("");
std::snprintf(buf.get(), size_buf, format.c_str(), args ...);
return std::string(buf.get(), buf.get() + size_buf - 1);
}
//----------------------------------------------------------------------------------------
net_adapter_helper() = default;
virtual ~net_adapter_helper() = default;
net_adapter_helper(const net_adapter_helper& instance) = delete;
net_adapter_helper& operator = (const net_adapter_helper& instance) = delete;
net_adapter_helper(const net_adapter_helper&& instance) = delete;
net_adapter_helper& operator = (const net_adapter_helper&& instance) = delete;
};
}
- 3.2 源文件源码
#include "ip_helper.h"
#include <memory>
#include <string>
#if defined(os_is_win)
#include <WinSock2.h>
#include <Iphlpapi.h>
#endif //! defined(os_is_win)
namespace lib_net
{
/**
* @brief:
*/
lib_net::net_adapter_helper& net_adapter_helper::get_instance()
{
static net_adapter_helper instance;
return instance;
}
/**
* @brief:
*/
lib_net::net_ada_list net_adapter_helper::get_info_win()
{
net_ada_list ret_list;
std::unique_ptr< IP_ADAPTER_INFO> pai(new(std::nothrow) IP_ADAPTER_INFO);
// 1. failed to apply space
if (nullptr == pai || NULL == pai)
return ret_list;
// 2. to get the size of IP_ADAPTER_INFO structure
unsigned long iai_size = sizeof(IP_ADAPTER_INFO);
// 3.调用GetAdaptersInfo函数, 填充pIpAdapterInfo指针变量; 其中stSize参数既是一个输入量也是一个输出量
int ret_val = GetAdaptersInfo(pai.get(), &iai_size);
if (ERROR_BUFFER_OVERFLOW == ret_val)
{
pai.release();
//重新申请内存空间用来存储所有网卡信息
pai.reset((IP_ADAPTER_INFO*)(new(std::nothrow) char[iai_size]));
if (nullptr == pai || NULL == pai)
{
return ret_list;
}
//再次调用GetAdaptersInfo函数,填充pIpAdapterInfo指针变量
ret_val = GetAdaptersInfo(pai.get(), &iai_size);
}
if (ERROR_SUCCESS == ret_val)
{
// 3. to get information
net_ada_info item;
IP_ADAPTER_INFO *ppai = pai.get();
while (ppai)
{
item._index = ppai->Index;
item._name = std::string(ppai->AdapterName);
item._description = std::string(ppai->Description);
// dev
std::string str_type;
switch (ppai->Type)
{
case MIB_IF_TYPE_OTHER:
str_type = {"OTHER"};
break;
case MIB_IF_TYPE_ETHERNET:
str_type = { "ETHERNET" };
break;
case MIB_IF_TYPE_TOKENRING:
str_type = { "TOKENRING" };
break;
case MIB_IF_TYPE_FDDI:
str_type = { "FDDI" };
break;
case MIB_IF_TYPE_PPP:
str_type = { "PPP" };
break;
case MIB_IF_TYPE_LOOPBACK:
str_type = { "LOOPBACK" };
break;
case MIB_IF_TYPE_SLIP:
str_type = { "SLP" };
break;
default:
str_type = { "" };
break;
}
item._dev_type = str_type;
// mac
std::string str_mac;
for (DWORD i = 0; i < ppai->AddressLength; i++)
{
if (i < ppai->AddressLength - 1)
str_mac += str_format("%02X-", ppai->Address[i]);
else
str_mac += str_format("%02X", ppai->Address[i]);
}
item._mac = str_mac;
// ip information
ip_info ii_item;
IP_ADDR_STRING *pial = &(ppai->IpAddressList);
int ip_size = 0;
for (;;)
{
if (NULL != pial && nullptr != pial)
{
ii_item._inet4 = std::string(pial->IpAddress.String);
ii_item._subnet_mask = std::string(pial->IpMask.String);
ii_item._gate = std::string(pai->GatewayList.IpAddress.String);
item._ip.push_back(ii_item);
pial = pial->Next;
ii_item.zero();
ip_size++;
}
else
{
break;
}
}
item._ip_size = ip_size;
ret_list.push_back(item);
item.zero();
ppai = ppai->Next;
} // end while
}
else
{
;// error
}
return ret_list;
}
}
4.使用
net_ada_list nal = net_adapter_helper::get_instance().get_info_win();
int list_size = nal.size();
cout << "1.适配器数目 = " << list_size << "\n\n" << endl;
#if defined(os_is_win)
for (auto item : nal)
{
cout << "索引=" << item._index << endl;
cout << "名字=" << item._name.c_str() << endl;
cout << "描述=" << item._description.c_str() << endl;
cout << "类型=" << item._dev_type.c_str() << endl;
cout << "MAC=" << item._mac.c_str() << endl;
int index = 0;
cout << "ip有=" << item._ip_size << "个" << endl;
for (auto item_ip : item._ip)
{
cout << "第" << ++index << "个ip" << endl;
cout << "ipv4 = " << item_ip._inet4.c_str() << endl;
cout << "子网掩码 = " << item_ip._subnet_mask.c_str() << endl;
cout << "网关 = " << item_ip._gate.c_str() << endl;
cout << "\n-------------------------";
}
cout << "\n--------------------------------------------------\n\n";
}
#endif //