Windows10 c++获取网卡信息(ipv4,子网掩码,网关,mac地址)

时间:2024-02-22 17:23:55

关于

本文样式环境: 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 //