English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

طرق الحصول على معلومات IP وMAC لجميع بطاقات الشبكة المحلية في C++

قد تكون هناك أكثر من بطاقة شبكة واحدة على جهاز واحد، ولكن كل بطاقة شبكة تحتوي على عنوان MAC واحد فقط، وكل بطاقة شبكة قد تكون مزودة بعدة عناوين IP؛ مثل الحاسوب المحمول العادي، الذي يحتوي على بطاقة شبكة لاسلكية و بطاقة شبكة بتوصيل شبكة (مخرج شبكة)؛ لذلك، إذا كنت ترغب في الحصول على معلومات جميع بطاقات الشبكة الخاصة بك لعناوين IP و MAC، يجب أن تحصل بشكل متسلسل على كل بطاقة شبكة، ثم الحصول على معلوماتها بشكل متسلسل؛ في sdk windows، يتم استخدام هيكل IP_ADAPTER_INFO لتخزين معلومات بطاقة الشبكة، بما في ذلك اسم بطاقة الشبكة، ووصف بطاقة الشبكة، عنوان MAC لبطاقة الشبكة، وعناوين IP لبطاقة الشبكة، وغيرها، ويمكن وصف هذا الهيكل كما يلي:

typedef struct _IP_ADAPTER_INFO {
  struct _IP_ADAPTER_INFO* Next;//指向链表中下一个适配器信息的指针
  DWORD ComboIndex;//预留值
  char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];//使用ANSI字符串表示的适配器名称
  char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];//使用ANSI字符串表示的适配器描述
  UINT AddressLength;//适配器硬件地址以字节计算的长度
  BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];//硬件地址以BYTE数组所表示
  DWORD Index;//适配器索引
  UINT Type;//适配器类型,主要有以下几种:
  /*
   *  MIB_IF_TYPE_OTHER   1
   *  MIB_IF_TYPE_ETHERNET   6
   *  MIB_IF_TYPE_TOKENRING   9
   *  MIB_IF_TYPE_FDDI   15
   *  MIB_IF_TYPE_PPP   23
   *  MIB_IF_TYPE_LOOPBACK   24
   *  MIB_IF_TYPE_SLIP   28
   */
  UINT DhcpEnabled;//指定这个适配器是否开启DHCP
  PIP_ADDR_STRING CurrentIpAddress;//预留值
  IP_ADDR_STRING IpAddressList;//该适配器的IPv4地址链表
  IP_ADDR_STRING GatewayList;//该适配器的网关IPv4地址链表
  IP_ADDR_STRING DhcpServer;//该适配器的DHCP服务器的IPv4 地址链表
  BOOL HaveWins;
  IP_ADDR_STRING PrimaryWinsServer;
  IP_ADDR_STRING SecondaryWinsServer;
  time_t LeaseObtained;
  time_t LeaseExpires;
  }; IP_ADAPTER_INFO,*PIP_ADAPTER_INFO;

بما أن هناك قد تكون هناك عدة بطاقات شبكة، فإن حقل struct _IP_ADAPTER_INFO* Next هو إشارة إلى بنية قائمة، وبما أن بطاقة الشبكة قد تحتوي على عدة عناوين، فإن حقل IP_ADDR_STRING يجب أن يكون أيضًا بنية قائمة، وتكون المعلومات كما يلي:

typedef struct _IP_ADDR_STRING
{
  struct _IP_ADDR_STRING* Next; // يشير إلى العنصر التالي من نفس النوع، أي العنوان التالي (إذا كان هناك عناوين متعددة)
  IP_ADDRESS_STRING IpAddress; // معلومات عنوان الشبكة
  IP_MASK_STRING IpMask; // ماسك عنوان الشبكة
  DWORD Context; // مدخل قائمة الشبكة. هذا القيمة تتناسب مع NTEContext في دوال AddIPAddredd وDeleteIPAddress
}; IP_ADDR_STRING;

بشكل عام، يمكن استخدام الشكل التالي لوصف معلومات تخزين بنية بطاقة الشبكة، مما يجعلها أكثر وضوحًا:

بعد فهم هذه المعلومات الأساسية، يمكنك استدعاء دالة GetAdaptersInfo للحصول على معلومات بطاقات الشبكة، ويكون الكود العادي كما يلي:

#include <WinSock2.h>
#include <Iphlpapi.h>
#include <iostream>
using namespace std;
#pragma comment(lib,"Iphlpapi.lib") //需要添加Iphlpapi.lib库
int main(int argc, char* argv[])
{
  //PIP_ADAPTER_INFO结构体指针存储本机网卡信息
  PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO();
  //得到结构体大小,用于GetAdaptersInfo参数
  unsigned long stSize = sizeof(IP_ADAPTER_INFO);
  //调用GetAdaptersInfo函数,填充pIpAdapterInfo指针变量;其中stSize参数既是一个输入量也是一个输出量
  int nRel = GetAdaptersInfo(pIpAdapterInfo,&stSize);
  //记录网卡数量
  int netCardNum = 0;
  // تسجيل عدد عناوين IP على كل بطاقة شبكية
  int IPnumPerNetCard = 0;
  if (ERROR_BUFFER_OVERFLOW == nRel)
  {
    // إذا كان العائد للوظيفة ERROR_BUFFER_OVERFLOW
    // هذا يعني أن مساحة الذاكرة المقدمة لـ GetAdaptersInfo غير كافية، كما أن stSize تعبر عن الحجم المطلوب
    // هذا هو السبب في أن stSize هو كلا الدخل والخروج
    // يتم إطلاق المساحة الذاكرية السابقة
    delete pIpAdapterInfo;
    // يتم إعادة تعيين مساحة الذاكرة لاستيعاب جميع معلومات بطاقات الشبكة
    pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize];
    // يتم استدعاء GetAdaptersInfo مرة أخرى لملء متغير الدالة pIpAdapterInfo
    nRel=GetAdaptersInfo(pIpAdapterInfo,&stSize);  
  {}
  if (ERROR_SUCCESS == nRel)
  {
    // عرض معلومات بطاقة الشبكة
     // قد تكون هناك بطاقات شبكية متعددة، لذا يتم استخدام الدائرة لتحديد ذلك
  while (pIpAdapterInfo)
  {
    cout<<"عدد بطاقات الشبكة:"<<++netCardNum<<endl;
    cout<<"اسم بطاقة الشبكة:"<<pIpAdapterInfo->AdapterName<<endl;
    cout<<"وصف بطاقة الشبكة:"<<pIpAdapterInfo->Description<<endl;
    switch(pIpAdapterInfo->Type)
    {
    case MIB_IF_TYPE_OTHER:
      cout<<"نوع بطاقة الشبكة:"<<"OTHER"<<endl;
      break;
    case MIB_IF_TYPE_ETHERNET:
      cout<<"نوع بطاقة الشبكة:"<<"ETHERNET"<<endl;
      break;
    case MIB_IF_TYPE_TOKENRING:
      cout<<"نوع بطاقة الشبكة:"<<"TOKENRING"<<endl;
      break;
    case MIB_IF_TYPE_FDDI:
      cout<<"نوع بطاقة الشبكة:"<<"FDDI"<<endl;
      break;
    case MIB_IF_TYPE_PPP:
      printf("PP\n");
      cout<<"نوع بطاقة الشبكة:"<<"PPP"<<endl;
      break;
    case MIB_IF_TYPE_LOOPBACK:
      cout<<"نوع بطاقة الشبكة:"<<"LOOPBACK"<<endl;
      break;
    case MIB_IF_TYPE_SLIP:
      cout<<"نوع الجهاز الشبكي: "<<"SLIP"<<endl;
      break;
    default:
      break;
    {}
    cout<<"عنوان MAC للجهاز الشبكي: ";
    for (DWORD i = 0; i < pIpAdapterInfo->AddressLength; i++)
      if (i < pIpAdapterInfo->AddressLength-1)
      {
        printf("%02X-", pIpAdapterInfo->Address[i]);
      {}
      else
      {
        printf("%02X\n", pIpAdapterInfo->Address[i]);
      {}
      cout<<"عناوين IP للجهاز الشبكي: "<<endl;
      //قد يكون لدي الجهاز الشبكي عدة عناوين IP، لذا يتم التحقق من ذلك بالدور
      IP_ADDR_STRING *pIpAddrString =&(pIpAdapterInfo->IpAddressList);
      do 
      {
        cout<<"عدد عناوين IP على هذا الجهاز الشبكي: "<<++IPnumPerNetCard<<endl;
        cout<<"عنوان IP: "<<pIpAddrString->IpAddress.String<<endl;
        cout<<"عنوان الشبكة: "<<pIpAddrString->IpMask.String<<endl;
        cout<<"عنوان واجهة الشبكة: "<<pIpAdapterInfo->GatewayList.IpAddress.String<<endl;
        pIpAddrString=pIpAddrString->Next;
      } while (pIpAddrString);
      pIpAdapterInfo = pIpAdapterInfo->Next;
      cout<<"--------------------------------------------------------------------"<<endl;
  {}
  {}
  //تحرير مساحة الذاكرة
  if (pIpAdapterInfo)
  {
    delete pIpAdapterInfo;
  {}
  return 0;
{}

نتيجة التنفيذ:

طريقة الحصول على عنوان IP الثاني:

#include <winsock.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib") //لرابط إلى مكتبة ws2_32.lib هذه
void CheckIP(void) // دالة CheckIP، تستخدم للحصول على عنوان IP للمستضيف
{
 WORD wVersionRequested; // متغير نوع WORD، يستخدم لتخزين قيمة إصدار Winsock
 WSADATA wsaData;
 char name[255]; // تستخدم لتخزين اسم المستضيف
 PHOSTENT hostinfo;
 wVersionRequested=MAKEWORD(2,0);
 // دعوة دالة MAKEWORD() للحصول على إصدار Winsock، واستخدامه لتحميل مكتبة Winsock
 if(WSAStartup(wVersionRequested,&wsaData) == 0)
 {
 // تحميل مكتبة Winsock، إذا كان عودة دالة WSAStartup() تساوي 0، فإن ذلك يعني نجاح التحميل
 if(gethostname(name,sizeof(name))==0)
 {
  if((hostinfo = gethostbyname(name) )!= NULL)
  {
  // إذا تم الحصول على اسم المستضيف بنجاح، يتم دعوة دالة inet_ntoa() للحصول على عنوان IP
  LPCSTR ip = inet_ntoa(*(struct in_addr *)*hostinfo->h_addr_list);
  printf("عنوان IP لهذا الجهاز:%s\n",ip); // عرض عنوان IP
  printf("اسم هذا الجهاز:%s\n",name);
  {}
 {}
 WSACleanup();
 {}
{}
int main()
{
 CheckIP(); // دعوة دالة CheckIP() للحصول على عرض عنوان IP
 return 0;
{}

وهذا هو كل محتوى تنفيذ طريقة الحصول على معلومات IP و MAC لجميع بطاقات الشبكة الخاصة بك في C++ الذي قدمه لك المحرر، نأمل أن تشجعوا دائمًا على دعم تعليماتي~

أعجبك ذلك