C语言获取硬件信息(CPU序列号,硬盘序列号,网卡IP、MAC地址、是否插入网线)

一、前言

  本文主要介绍Linux和Windows下使用C语言获取各种硬件信息,包括CPU序列号、硬盘序列号、网卡信息(包括网卡名字、IP地址、MAC地址、网卡是否插入网线等)。

二、代码实现

Linux下所需包含的头文件

#include <linux/hdreg.h>
#include <fcntl.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <unistd.h>
#include <sys/io.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <sys/ioctl.h>

Windows下所需包含的头文件

#include <iostream>
#include <string>
#include <windows.h>
#include <iphlpapi.h>

2.1 获取CPU序列号

  1. Linux下获取CPU序列号,也就是id,经过实测发现,相同厂家相同型号的CPU的序列号是一样的。
/**
 * @brief getCpuId     获取Linux下的CPU序列号
 * @param id     存储获取到的CPU序列号的字符串变量
 * @return       0:获取成功  其他返回值:获取失败
*/
int getCpuId(char *id)
{
    unsigned int s1,s2;
    asm volatile
    ( "movl $0x01,%%eax ; \n\t"
      "xorl %%edx,%%edx ;\n\t"
      "cpuid ;\n\t"
      "movl %%edx , %0;\n\t"
      "movl %%eax , %1;\n\t"
      :"=m"(s1),"=m"(s2)
    );
    if(0 == s1 && 0 == s2) {
        return -1;
    }
    char cpu_id[32] = {0};
    sprintf(cpu_id, "%08X-%08X", htonl(s2), htonl(s1));
    strcpy(id, cpu_id);
    return 0;
}
  1. Windows下获取CPU序列号,也就是id,经过实测发现,相同厂家相同型号的CPU的序列号是一样的。

/**
 * @brief GetCpuByCmd     获取windows下的CPU序列号
 * @param ider            获取到的CPU序列号的字符串变量
 * @return                true:获取成功  false:获取失败
*/
bool GetCpuByCmd(string &ider)
{
    //CPU序列号
    const long MAX_COMMAND_SIZE = 64;                   //命令行输出缓冲大小
    WCHAR szFetCmd[] = L"wmic cpu get processorid";     //获取CPU序列号命令行
    const string strEnSearch = "ProcessorId";           //CPU序列号前导信息
    BOOL bret = FALSE;
    HANDLE hReadPipe = NULL;                            //读取管道
    HANDLE hWritePipe = NULL;                           //写入管道
    PROCESS_INFORMATION pi;                             //进程信息
    STARTUPINFO si;                                     //控制命令行窗口信息
    SECURITY_ATTRIBUTES sa;                             //安全属性

    char szBuffer[MAX_COMMAND_SIZE + 1] = {0};          //放置命令行结果的输出缓存区
    string strBuffer;
    unsigned long count = 0;
    long ipos = 0;
    
    memset(&pi , 0 , sizeof(pi));
    memset(&si , 0 , sizeof(si));
    memset(&sa , 0 , sizeof(sa));

    //初始化管道
    pi.hProcess = NULL;
    pi.hThread = NULL;
    si.cb = sizeof(STARTUPINFO);
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
    
    //创建管道
    bret = CreatePipe(&hReadPipe , &hWritePipe , &sa , 0);
    if(!bret) {
        CloseHandle(hWritePipe);
        CloseHandle(hReadPipe);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    //设置命令行窗口的信息为指定的读写管道
    GetStartupInfo(&si);
    si.hStdError = hWritePipe;
    si.hStdOutput = hWritePipe;
    si.wShowWindow = SW_HIDE;           //隐藏命令行窗口
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

    //创建获取命令行的进程
    bret = CreateProcess(NULL , szFetCmd , NULL , NULL , TRUE , 0 , NULL , NULL , &si , &pi);
    if(!bret) {
        CloseHandle(hWritePipe);
        CloseHandle(hReadPipe);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    //读取返回的数据
    WaitForSingleObject(pi.hProcess , 500);
    bret = ReadFile(hReadPipe , szBuffer , MAX_COMMAND_SIZE , &count , 0);
    if(!bret) {
        CloseHandle(hWritePipe);
        CloseHandle(hReadPipe);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    //查找CPU序列号
    bret = FALSE;
    strBuffer = szBuffer;
    ipos = strBuffer.find(strEnSearch);
    if(ipos < 0) {	//没有找到
        CloseHandle(hWritePipe);
        CloseHandle(hReadPipe);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    else {
        strBuffer = strBuffer.substr(ipos + strEnSearch.length());
    }
    memset(szBuffer , 0x00 , sizeof(szBuffer));
    strcpy_s(szBuffer , strBuffer.c_str());

    //去掉中间的空格\r\n
    char temp[512];
    memset(temp , 0 , sizeof(temp));
    int index = 0;
    for(size_t i = 0 ; i < strBuffer.size() ; i++) {
        if(strBuffer[i] != ' ' && strBuffer[i] != '\n' && strBuffer[i] != '\r') {
            temp[index] = strBuffer[i];
            index++;
        }
    }
    ider = temp;
    return true;
}

2.2 获取硬盘序列号

  1. Linux下获取硬盘序列号。
/**
 * @brief removeBlank  删除字符串中的空格
 * @param str          需要处理的字符串
 * @return             无返回值
*/
void removeBlank(char *str)
{
    char *str_c = str;
    int i,j=0;
    for(i=0;str[i]!='\0';i++) {
        if(str[i]!=' ') {
            str_c[j++]=str[i];
		}
    }
    str_c[j]='\0';
    str = str_c;
}

/**
 * @brief getDiskId       获取Linux下的硬盘序列号
 * @param hd_name         硬盘所在位置 例:/dev/sda
 * @param id              存储获取到的硬盘序列号的字符串变量
 * @return                0:获取成功  其他返回值:获取失败
*/
int getDiskId(char *hd_name, char *id)
{
    struct hd_driveid hid;
    int fd = open(hd_name,O_RDONLY | O_NONBLOCK);
    if(fd <0) {
        perror("open fd");
        return -1;
    }
    if(ioctl(fd,HDIO_GET_IDENTITY,&hid)<0) {
        perror("ioctl");
        return -1;
    }
    close(fd);
    char disk_id[32] = {0};
    sprintf(disk_id, "%s", hid.serial_no);
    removeBlank(disk_id); //删除字符串中的空格
    strcpy(id, disk_id);
    return 0;
}
  1. Windows下获取硬盘序列号。
/**
 * @brief GetDiskByCmd    获取windows下的硬盘序列号
 * @param ider            获取到的硬盘序列号的字符串变量
 * @return                true:获取成功  false:获取失败
*/
bool GetDiskByCmd(string &ider)
{
    //硬盘序列号
    const long MAX_COMMAND_SIZE = 64;                          //命令行输出缓冲大小
    WCHAR szFetCmd[] = L"wmic diskdrive get serialnumber";     //获取CPU序列号命令行
    const string strEnSearch = "SerialNumber";                 //CPU序列号前导信息
    BOOL bret = FALSE;
    HANDLE hReadPipe = NULL;                                   //读取管道
    HANDLE hWritePipe = NULL;                                  //写入管道
    PROCESS_INFORMATION pi;                                    //进程信息
    STARTUPINFO si;                                            //控制命令行窗口信息
    SECURITY_ATTRIBUTES sa;                                    //安全属性

    char szBuffer[MAX_COMMAND_SIZE + 1] = {0};                 //放置命令行结果的输出缓存区
    string strBuffer;
    unsigned long count = 0;
    long ipos = 0;

    memset(&pi, 0, sizeof(pi));
    memset(&si, 0, sizeof(si));
    memset(&sa, 0, sizeof(sa));

    //初始化管道
    pi.hProcess = NULL;
    pi.hThread = NULL;
    si.cb = sizeof(STARTUPINFO);
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;

    //创建管道
    bret = CreatePipe(&hReadPipe, &hWritePipe, &sa, 0);
    if(!bret) {
        CloseHandle(hWritePipe);
        CloseHandle(hReadPipe);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    //设置命令行窗口的信息为指定的读写管道
    GetStartupInfo(&si);
    si.hStdError = hWritePipe;
    si.hStdOutput = hWritePipe;
    si.wShowWindow = SW_HIDE;           //隐藏命令行窗口
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

    //创建获取命令行的进程
    bret = CreateProcess(NULL, szFetCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
    if(!bret) {
        CloseHandle(hWritePipe);
        CloseHandle(hReadPipe);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    //读取返回的数据
    WaitForSingleObject(pi.hProcess , 500);
    bret = ReadFile(hReadPipe, szBuffer, MAX_COMMAND_SIZE, &count, 0);
    if(!bret) {
        CloseHandle(hWritePipe);
        CloseHandle(hReadPipe);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    //查找CPU序列号
    bret = FALSE;
    strBuffer = szBuffer;
    ipos = strBuffer.find(strEnSearch);
    if(ipos < 0) {	//没有找到
        CloseHandle(hWritePipe);
        CloseHandle(hReadPipe);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    else {
        strBuffer = strBuffer.substr(ipos + strEnSearch.length());
    }
    memset(szBuffer, 0x00, sizeof(szBuffer));
    strcpy_s(szBuffer, strBuffer.c_str());

    //去掉中间的空格\r\n
    char temp[512];
    memset(temp , 0 , sizeof(temp));
    int index = 0;
    for(size_t i = 0; i < strBuffer.size(); i++) {
        if(strBuffer[i] != ' ' && strBuffer[i] != '\n' && strBuffer[i] != '\r') {
            temp[index] = strBuffer[i];
            index++;
        }
    }
    ider = temp;
    return true;
}

2.3 获取网卡信息

  1. Linux下获取网卡信息,包括网卡名字、IP地址、MAC地址、是否已经插入网线等信息。
//网卡信息结构体1
typedef struct __net_iface {
    int  sum_n;
    char net_name1[20];
    char net_name2[20];
    char net_name3[20];
    char net_name4[20];
    char net_name5[20];
    char net_ip1[16];
    char net_ip2[16];
    char net_ip3[16];
    char net_ip4[16];
    char net_ip5[16];
    char net_mac1[32];
    char net_mac2[32];
    char net_mac3[32];
    char net_mac4[32];
    char net_mac5[32];
}net_iface;

//网卡信息结构体2
struct net_iface_1 {
    struct net_iface_1 *next; //指向下一个网卡信息结构体的地址
    char net_name[20];          //网卡名字
    char net_ip[16];            //网卡IP
};

/**
 * @brief get_iface_name 获取网口名字
 * @param get_iface      OUT 结构体
 * @return               成功返回1 错误返回负数
 */
int get_iface_name(net_iface *get_iface)
{
    int sock_get_iface;
    struct ifconf ifc_get_iface;
    struct ifreq *ifr_get_iface;
    //初始化 ifconf
    char buf[512];
    ifc_get_iface.ifc_len = 512;
    ifc_get_iface.ifc_buf = buf;
    memset(get_iface,0,sizeof(net_iface));

    sock_get_iface = socket(AF_INET,SOCK_DGRAM,0);
    if(sock_get_iface < 0) {
        perror("SOCKET:");
        return -1;
    }
    if(ioctl(sock_get_iface ,SIOCGIFCONF,&ifc_get_iface) < 0) {
        perror("ioctl");
        return -1;
    }
    ifr_get_iface = (struct ifreq*)buf;
    get_iface->sum_n = ifc_get_iface.ifc_len/sizeof(struct ifreq);
    int control_n = 1;
    for(int i = (ifc_get_iface.ifc_len/sizeof(struct ifreq)); i > 0; i--) {
        if(strcmp(inet_ntoa(((struct sockaddr_in*)&(ifr_get_iface->ifr_addr))->sin_addr),"127.0.0.1") == 0) {
            ifr_get_iface++;
            get_iface->sum_n--;
            continue;
        }
        else {   
		switch (control_n) {
            case 1:
                strcpy(get_iface->net_name1,ifr_get_iface->ifr_name);
                strcpy(get_iface->net_ip1,inet_ntoa(((struct sockaddr_in*)&(ifr_get_iface->ifr_addr))->sin_addr));
                break;
            case 2:
                strcpy(get_iface->net_name2,ifr_get_iface->ifr_name);
                strcpy(get_iface->net_ip2,inet_ntoa(((struct sockaddr_in*)&(ifr_get_iface->ifr_addr))->sin_addr));
                break;
            case 3:
                strcpy(get_iface->net_name3,ifr_get_iface->ifr_name);
                strcpy(get_iface->net_ip3,inet_ntoa(((struct sockaddr_in*)&(ifr_get_iface->ifr_addr))->sin_addr));
                break;
            case 4:
                strcpy(get_iface->net_name4,ifr_get_iface->ifr_name);
                strcpy(get_iface->net_ip4,inet_ntoa(((struct sockaddr_in*)&(ifr_get_iface->ifr_addr))->sin_addr));
                break;
            case 5:
                strcpy(get_iface->net_name5,ifr_get_iface->ifr_name);
                strcpy(get_iface->net_ip5,inet_ntoa(((struct sockaddr_in*)&(ifr_get_iface->ifr_addr))->sin_addr));
                break;
            default:
                break;
            }
        }
        control_n++;
        ifr_get_iface++;
    }
    close(sock_get_iface);
    return 1;
}

/**
 * @brief getNetMac         获取Linux下的所有网卡MAC序列号(最多五个网卡设备)
 * @param get_iface         存储网卡信息的结构体
 * @return                  0:获取成功  其他返回值:获取失败
*/
int getNetMac(net_iface *get_iface)
{
    int i = 0;
    int sock;
    get_iface_name(get_iface);
    //printf("get_iface->sum_n: %d\n",get_iface->sum_n);
    for(i=1;i<=get_iface->sum_n;i++) {
        switch(i) {
            case 1:
                if((sock = socket(AF_INET,SOCK_STREAM,0))<0) {
                    perror("socket");
                    return 2;
                }
                struct ifreq ifreq1;
                strcpy(ifreq1.ifr_name,get_iface->net_name1);
                printf("%s ",ifreq1.ifr_name);
                if(ioctl(sock,SIOCGIFHWADDR,&ifreq1)<0) {
                    perror("ioctl ");
                    return 3;
                }
                sprintf(get_iface->net_mac1,"%02x:%02x:%02x:%02x:%02x:%02x",
                   (unsigned char)ifreq1.ifr_hwaddr.sa_data[0],
                   (unsigned char)ifreq1.ifr_hwaddr.sa_data[1],
                   (unsigned char)ifreq1.ifr_hwaddr.sa_data[2],
                   (unsigned char)ifreq1.ifr_hwaddr.sa_data[3],
                   (unsigned char)ifreq1.ifr_hwaddr.sa_data[4],
                   (unsigned char)ifreq1.ifr_hwaddr.sa_data[5]);
                printf("MAC1: %s\n",get_iface->net_mac1);
                close(sock);
                break;
            case 2:
                if((sock = socket(AF_INET,SOCK_STREAM,0))<0) {
                    perror("socket");
                    return 2;
                }
                struct ifreq ifreq2;
                strcpy(ifreq2.ifr_name,get_iface->net_name2);
                printf("%s ",ifreq2.ifr_name);
                if(ioctl(sock,SIOCGIFHWADDR,&ifreq2)<0) {
                    perror("ioctl ");
                    return 3;
                }
                sprintf(get_iface->net_mac2,"%02x:%02x:%02x:%02x:%02x:%02x",
                   (unsigned char)ifreq2.ifr_hwaddr.sa_data[0],
                   (unsigned char)ifreq2.ifr_hwaddr.sa_data[1],
                   (unsigned char)ifreq2.ifr_hwaddr.sa_data[2],
                   (unsigned char)ifreq2.ifr_hwaddr.sa_data[3],
                   (unsigned char)ifreq2.ifr_hwaddr.sa_data[4],
                   (unsigned char)ifreq2.ifr_hwaddr.sa_data[5]);
                printf("MAC2: %s\n",get_iface->net_mac2);
                close(sock);
                break;
            case 3:
                if((sock = socket(AF_INET,SOCK_STREAM,0))<0) {
                    perror("socket");
                    return 2;
                }
                struct ifreq ifreq3;
                strcpy(ifreq3.ifr_name,get_iface->net_name3);
                printf("%s ",ifreq3.ifr_name);
                if(ioctl(sock,SIOCGIFHWADDR,&ifreq3)<0) {
                    perror("ioctl ");
                    return 3;
                }
                sprintf(get_iface->net_mac3,"%02x:%02x:%02x:%02x:%02x:%02x",
                   (unsigned char)ifreq3.ifr_hwaddr.sa_data[0],
                   (unsigned char)ifreq3.ifr_hwaddr.sa_data[1],
                   (unsigned char)ifreq3.ifr_hwaddr.sa_data[2],
                   (unsigned char)ifreq3.ifr_hwaddr.sa_data[3],
                   (unsigned char)ifreq3.ifr_hwaddr.sa_data[4],
                   (unsigned char)ifreq3.ifr_hwaddr.sa_data[5]);
                printf("MAC3: %s\n",get_iface->net_mac3);
                close(sock);
                break;
            case 4:
                if((sock = socket(AF_INET,SOCK_STREAM,0))<0) {
                    perror("socket");
                    return 2;
                }
                struct ifreq ifreq4;
                strcpy(ifreq4.ifr_name,get_iface->net_name4);
                printf("%s ",ifreq4.ifr_name);
                if(ioctl(sock,SIOCGIFHWADDR,&ifreq4)<0) {
                    perror("ioctl ");
                    return 3;
                }
                sprintf(get_iface->net_mac4,"%02x:%02x:%02x:%02x:%02x:%02x",
                   (unsigned char)ifreq4.ifr_hwaddr.sa_data[0],
                   (unsigned char)ifreq4.ifr_hwaddr.sa_data[1],
                   (unsigned char)ifreq4.ifr_hwaddr.sa_data[2],
                   (unsigned char)ifreq4.ifr_hwaddr.sa_data[3],
                   (unsigned char)ifreq4.ifr_hwaddr.sa_data[4],
                   (unsigned char)ifreq4.ifr_hwaddr.sa_data[5]);
                printf("MAC4: %s\n",get_iface->net_mac4);
                close(sock);
                break;
            case 5:
                if((sock = socket(AF_INET,SOCK_STREAM,0))<0) {
                    perror("socket");
                    return 2;
                }
                struct ifreq ifreq5;
                strcpy(ifreq5.ifr_name,get_iface->net_name5);
                printf("%s ",ifreq5.ifr_name);
                if(ioctl(sock,SIOCGIFHWADDR,&ifreq5)<0) {
                    perror("ioctl ");
                    return 3;
                }
                sprintf(get_iface->net_mac5,"%02x:%02x:%02x:%02x:%02x:%02x",
                   (unsigned char)ifreq5.ifr_hwaddr.sa_data[0],
                   (unsigned char)ifreq5.ifr_hwaddr.sa_data[1],
                   (unsigned char)ifreq5.ifr_hwaddr.sa_data[2],
                   (unsigned char)ifreq5.ifr_hwaddr.sa_data[3],
                   (unsigned char)ifreq5.ifr_hwaddr.sa_data[4],
                   (unsigned char)ifreq5.ifr_hwaddr.sa_data[5]);
                printf("MAC5: %s\n",get_iface->net_mac5);
                close(sock);
                break;
        }
    }
    return 0;
}

/**
 * @brief check_nic    检测网卡是否已经插上网线
 * @param eth_name     IN 网卡名字
 * @return             0:网卡已插上网线   -1:网卡未插上网线      其他返回值:错误
 */
int check_nic(const char *net_name)
{
    struct ifreq ifr;
    int skfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(skfd < 0) {
        qDebug("socket error: %s [%s]\n", strerror(errno), __FUNCTION__);
        return -2;
    }
    strcpy(ifr.ifr_name, net_name);
    if(ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
        close(skfd);
        return -3;
    }
    if(ifr.ifr_flags & IFF_RUNNING) {
        close(skfd);
        return 0; //网卡已插上网线
    }
    else {
        close(skfd);
        return -1;
    }
}

/**
 * @brief get_iface_info	   获取本地所有网卡名字和IP
 * @param netIface             网卡信息结构体指针,用户自行分配存储空间
 * @param outBuffLen           netIface分配的存储空间大小,若与实际获取到的数据总大小不一致,则将实际的总大小返回
 * @return                     0:成功
 *                             1:outBuffLen与实际获取到的数据总大小不一致,将实际的大小赋值给outBuffLen并返回
 *                             -1:错误
 * 使用步骤注意:
 * 1、malloc申请 netIface 堆内存空间,初始化 outBuffLen 变量的值
 * 2、调用一次该函数,目的是确定实际outBuffLen的大小
 * 3、判断返回值,如果返回1,则释放netIface堆内存空间,根据outBuffLen的大小重新分配堆内存空间;
 *    如果返回0,证明获取网卡信息成功,直接跳过第3、4步
 * 4、再一次调用该函数,若成功返回,则网卡信息获取完成
 * 5、遍历获取网卡信息,根据结构体的 next 指针即可遍历指向下一个网卡信息的地址,直到 next 为空
 */
int get_iface_info(net_iface_1 *netIface, unsigned int *outBuffLen)
{
    int sock_get_iface;
    struct ifconf ifc_get_iface;
    struct ifreq *ifr_get_iface;
    //初始化 ifconf
    char buf[512];
    ifc_get_iface.ifc_len = 512;
    ifc_get_iface.ifc_buf = buf;

    sock_get_iface = socket(AF_INET,SOCK_DGRAM,0);
    if(sock_get_iface < 0) {
        perror("SOCKET:");
        return -1;
    }
    if(ioctl(sock_get_iface ,SIOCGIFCONF,&ifc_get_iface) < 0) {
        perror("ioctl");
        return -1;
    }
    unsigned int num = (ifc_get_iface.ifc_len/sizeof(struct ifreq)); //网卡个数
    if(*outBuffLen != num * sizeof(net_iface_1)) {
        *outBuffLen = num * sizeof(net_iface_1);
        return 1;
    }
    memset(netIface, 0, *outBuffLen);
    ifr_get_iface = (struct ifreq*)buf;
    for(unsigned int i=0; i<num; i++) {
        strcpy(netIface[i].net_name, ifr_get_iface->ifr_name);
        strcpy(netIface[i].net_ip, inet_ntoa(((struct sockaddr_in*)&(ifr_get_iface->ifr_addr))->sin_addr));
        if(i == num - 1) {
            netIface[i].next = NULL;
        }
        else {
            netIface[i].next = netIface + (i + 1);
        }
        ifr_get_iface++;
    }
    close(sock_get_iface);
    return 0;
}
  1. Windows下获取网卡信息,包括网卡名字、IP地址、MAC地址、是否已经插入网线等信息。
// 网卡信息结构体
typedef struct _adapter_info {
    struct _adapter_info *next;             //指向下一个网卡信息结构体的地址
    char name[MAX_ADAPTER_NAME_LENGTH + 4]; //网卡名字
    unsigned long index;                    //网卡索引号
    char ipAddr[16];                        //网卡IP地址
    char gateway[16];                       //网卡网关
    char ipMask[16];                        //网卡掩码
    char macAddr[20];                       //网卡物理地址
}adapterInfo;

/**
 * @brief   getAdaptersInfo             获取网卡(网络适配器)的基本信息
 * @param   infoList                    获取到的各个网卡(网络适配器)的信息链表
 * @return  int                         0:成功
 *                                      1:outBuffLen与实际获取到的数据总大小不一致,将实际的大小赋值给outBuffLen并返回
 *                                     -1:失败
 * 使用步骤注意:
 * 1、malloc申请pInfo堆内存空间,初始化outBuffLen变量的值
 * 2、调用一次该函数,目的是确定实际outBuffLen的大小
 * 3、判断返回值,如果返回1,则释放pInfo堆内存空间,根据outBuffLen的大小重新分配堆内存空间;
 *    如果返回0,证明获取网卡信息成功,直接跳过第3、4步
 * 4、再一次调用该函数,若成功返回,则网卡信息获取完成
 * 5、遍历获取网卡信息,根据结构体的next指针即可遍历指向下一个网卡信息的地址,直到next为空
 */
int getAdaptersInfo(adapterInfo *pInfo, unsigned int *outBuffLen)
{
    PIP_ADAPTER_INFO pAdapterInfo;
    PIP_ADAPTER_INFO pAdapter = NULL;
    ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
    pAdapterInfo = (PIP_ADAPTER_INFO)malloc(ulOutBufLen);
    DWORD dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen); //第一次调用 getAdaptersInfo 获取 ulOutBufLen 的大小
    if(dwRetVal == ERROR_BUFFER_OVERFLOW) {
        free(pAdapterInfo);
        pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
        dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
    }
    if(dwRetVal == NO_ERROR) {
        pAdapter = pAdapterInfo;
        unsigned int adapterNum = 0;
        while(pAdapter) {
            adapterNum++;
            pAdapter = pAdapter->Next;
        }
        if(*outBuffLen != adapterNum * sizeof(adapterInfo)) {
            *outBuffLen = adapterNum * sizeof(adapterInfo);
            if(pAdapterInfo != NULL) {
                free(pAdapterInfo);
                pAdapterInfo = NULL;
                pAdapter = NULL;
            }
            return 1;
        }

        memset(pInfo, 0, *outBuffLen);
        pAdapter = pAdapterInfo;
        unsigned int currNum = 0;
        while(pAdapter) {
            memcpy(pInfo[currNum].name, pAdapter->AdapterName, sizeof(pAdapter->AdapterName)); //网卡名字
            pInfo[currNum].index = pAdapter->Index; //网卡索引号
            memcpy(pInfo[currNum].ipAddr, pAdapter->IpAddressList.IpAddress.String,
                   sizeof(pAdapter->IpAddressList.IpAddress.String)); //网卡IP地址
            memcpy(pInfo[currNum].gateway, pAdapter->GatewayList.IpAddress.String,
                   sizeof(pAdapter->GatewayList.IpAddress.String)); //网卡网关地址
            memcpy(pInfo[currNum].ipMask, pAdapter->IpAddressList.IpMask.String,
                   sizeof(pAdapter->IpAddressList.IpMask.String)); //网卡IP地址掩码
            char macAddr[sizeof(pInfo[currNum].macAddr)];
            memset(macAddr, 0, sizeof(macAddr));
            sprintf(macAddr, "%02X-%02X-%02X-%02X-%02X-%02X", pAdapter->Address[0], pAdapter->Address[1],
                    pAdapter->Address[2], pAdapter->Address[3], pAdapter->Address[4], pAdapter->Address[5]);
            memcpy(pInfo[currNum].macAddr, macAddr, sizeof(macAddr)); //网卡物理地址
            if(currNum == adapterNum - 1) {
                pInfo[currNum].next = NULL;
            }
            else {
                pInfo[currNum].next = pInfo + (currNum + 1);
            }
            currNum++;

            pAdapter = pAdapter->Next;
        }
        if(pAdapterInfo != NULL) {
            free(pAdapterInfo);
            pAdapterInfo = NULL;
            pAdapter = NULL;
        }
        return 0;
    }
    else {
        if(pAdapterInfo != NULL) {
            free(pAdapterInfo);
            pAdapterInfo = NULL;
        }
        printf("Call to tcpclient_getAdaptersInfo_1 failed.\n");
    }
    return -1;
}

/**
 * @brief   getAdapterState             获取网卡(网络适配器)的状态
 * @param   infoList                    网卡(网络适配器)索引号
 * @return  int                         0:正常    -1:网卡状态异常    -2:获取网卡状态失败
 */
int getAdapterState(unsigned long index)
{
    MIB_IFROW info;
    memset(&info, 0, sizeof(MIB_IFROW));
    info.dwIndex = index;
    if(GetIfEntry(&info) != NOERROR) {
        printf("ErrorCode = %d\n", GetLastError());
        return -2;
    }
    if(info.dwOperStatus == IF_OPER_STATUS_NON_OPERATIONAL || //局域网适配器禁用,例如地址冲突
       info.dwOperStatus == IF_OPER_STATUS_UNREACHABLE || //WAN适配器未连接
       info.dwOperStatus == IF_OPER_STATUS_DISCONNECTED || //局域网适配器:网线未插入   WAN适配器:无信号
       info.dwOperStatus == IF_OPER_STATUS_CONNECTING) {
        return -1;
    }
    else if(info.dwOperStatus == IF_OPER_STATUS_OPERATIONAL ||
            info.dwOperStatus == IF_OPER_STATUS_CONNECTED) {
        return 0;
    }
}

附:源代码下载

C语言获取硬件信息(CPU序列号,硬盘序列号,网卡IP、MAC地址、是否插入网线).zip

  • 6
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶落花枯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值