• Linux下C获取所有可用网卡信息


    在Linux下开发网络程序时,经常会遇到需要取本地网络接口名、IP、广播地址、子网掩码或者MAC地址等信息的需求,最常见的办法是配合宏SIOCGIFHWADDR、SIOCGIFADDR、SIOCGIFBRDADDR与SIOCGIFNETMASK作为参数调用函数ioctl分别获得MAC地址、IP地址、广播地址与子网掩码来实现。一次性获取此类信息的C语言代码实现如下。 

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <net/if.h>
      4 #include <sys/ioctl.h>
      5 #include <arpa/inet.h>
      6 #include <errno.h>
      7 
      8 int getLocalInfo(void)
      9 {
     10     int fd;
     11     int interfaceNum = 0;
     12     struct ifreq buf[16];
     13     struct ifconf ifc;
     14     struct ifreq ifrcopy;
     15     char mac[16] = {0};
     16     char ip[32] = {0};
     17     char broadAddr[32] = {0};
     18     char subnetMask[32] = {0};
     19 
     20     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
     21     {
     22         perror("socket");
     23 
     24         close(fd);
     25         return -1;
     26     }
     27 
     28     ifc.ifc_len = sizeof(buf);
     29     ifc.ifc_buf = (caddr_t)buf;
     30     if (!ioctl(fd, SIOCGIFCONF, (char *)&ifc))
     31     {
     32         interfaceNum = ifc.ifc_len / sizeof(struct ifreq);
     33         printf("interface num = %dn", interfaceNum);
     34         while (interfaceNum-- > 0)
     35         {
     36             printf("ndevice name: %sn", buf[interfaceNum].ifr_name);
     37 
     38             //ignore the interface that not up or not runing  
     39             ifrcopy = buf[interfaceNum];
     40             if (ioctl(fd, SIOCGIFFLAGS, &ifrcopy))
     41             {
     42                 printf("ioctl: %s [%s:%d]n", strerror(errno), __FILE__, __LINE__);
     43 
     44                 close(fd);
     45                 return -1;
     46             }
     47 
     48             //get the mac of this interface  
     49             if (!ioctl(fd, SIOCGIFHWADDR, (char *)(&buf[interfaceNum])))
     50             {
     51                 memset(mac, 0, sizeof(mac));
     52                 snprintf(mac, sizeof(mac), "%02x%02x%02x%02x%02x%02x",
     53                     (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[0],
     54                     (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[1],
     55                     (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[2],
     56 
     57                     (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[3],
     58                     (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[4],
     59                     (unsigned char)buf[interfaceNum].ifr_hwaddr.sa_data[5]);
     60                 printf("device mac: %sn", mac);
     61             }
     62             else
     63             {
     64                 printf("ioctl: %s [%s:%d]n", strerror(errno), __FILE__, __LINE__);
     65                 close(fd);
     66                 return -1;
     67             }
     68 
     69             //get the IP of this interface  
     70 
     71             if (!ioctl(fd, SIOCGIFADDR, (char *)&buf[interfaceNum]))
     72             {
     73                 snprintf(ip, sizeof(ip), "%s",
     74                     (char *)inet_ntoa(((struct sockaddr_in *)&(buf[interfaceNum].ifr_addr))->sin_addr));
     75                 printf("device ip: %sn", ip);
     76             }
     77             else
     78             {
     79                 printf("ioctl: %s [%s:%d]n", strerror(errno), __FILE__, __LINE__);
     80                 close(fd);
     81                 return -1;
     82             }
     83 
     84             //get the broad address of this interface  
     85 
     86             if (!ioctl(fd, SIOCGIFBRDADDR, &buf[interfaceNum]))
     87             {
     88                 snprintf(broadAddr, sizeof(broadAddr), "%s",
     89                     (char *)inet_ntoa(((struct sockaddr_in *)&(buf[interfaceNum].ifr_broadaddr))->sin_addr));
     90                 printf("device broadAddr: %sn", broadAddr);
     91             }
     92             else
     93             {
     94                 printf("ioctl: %s [%s:%d]n", strerror(errno), __FILE__, __LINE__);
     95                 close(fd);
     96                 return -1;
     97             }
     98  99 
    100             //get the subnet mask of this interface  
    101             if (!ioctl(fd, SIOCGIFNETMASK, &buf[interfaceNum]))
    102             {
    103                 snprintf(subnetMask, sizeof(subnetMask), "%s",
    104                     (char *)inet_ntoa(((struct sockaddr_in *)&(buf[interfaceNum].ifr_netmask))->sin_addr));
    105                 printf("device subnetMask: %sn", subnetMask);
    106             }
    107             else
    108             {
    109                 printf("ioctl: %s [%s:%d]n", strerror(errno), __FILE__, __LINE__);
    110                 close(fd);
    111                 return -1;
    112 
    113             }
    114         }
    115     }
    116     else
    117     {
    118         printf("ioctl: %s [%s:%d]n", strerror(errno), __FILE__, __LINE__);
    119         close(fd);
    120         return -1;
    121     }
    122   
    123     close(fd);
    124 
    125     return 0;
    126 }
    127   
    128 int main(void)
    129 {
    130     getLocalInfo();
    131 
    132     return 0;
    133 }

    使用ioctl函数虽然可以获取所有的信息,但是使用起来比较麻烦,如果不需要获取MAC地址,那么使用getifaddrs函数来获取更加方便与简洁。值得一提的是,在MacOS或iOS系统上(如iPhone程序开发),上述iotcl函数没法获得mac地址跟子网掩码,这个使用,使用getifaddrs函数便更有优势了。下面是使用getiaddrs函数获取网卡信息的C语言代码实现。

     1 #include <stdio.h>  
     2 #include <ifaddrs.h>  
     3 #include <arpa/inet.h>  
     4   
     5 int getSubnetMask()
     6 {
     7     struct sockaddr_in *sin = NULL;
     8     struct ifaddrs *ifa = NULL, *ifList;
     9 
    10     if (getifaddrs(&ifList) < 0)
    11     {
    12         return -1;
    13     }
    14 
    15     for (ifa = ifList; ifa != NULL; ifa = ifa->ifa_next)
    16     {
    17         if(ifa->ifa_addr->sa_family == AF_INET)
    18         {
    19             printf("n>>> interfaceName: %sn", ifa->ifa_name);
    20 
    21             sin = (struct sockaddr_in *)ifa->ifa_addr;
    22             printf(">>> ipAddress: %sn", inet_ntoa(sin->sin_addr));
    23 
    24             sin = (struct sockaddr_in *)ifa->ifa_dstaddr;
    25             printf(">>> broadcast: %sn", inet_ntoa(sin->sin_addr));
    26 
    27             sin = (struct sockaddr_in *)ifa->ifa_netmask;
    28             printf(">>> subnetMask: %sn", inet_ntoa(sin->sin_addr));
    29         }
    30     }
    31 
    32     freeifaddrs(ifList);
    33 
    34     return 0;
    35 }
    36   
    37 int main(void)
    38 {
    39     getSubnetMask();
    40 
    41     return 0;
    42 }

    ifaddrs结构体定义如下:

     1 struct ifaddrs   
     2 {   
     3     struct ifaddrs  *ifa_next;    /* Next item in list */   
     4     char            *ifa_name;    /* Name of interface */   
     5     unsigned int     ifa_flags;   /* Flags from SIOCGIFFLAGS */   
     6     struct sockaddr *ifa_addr;    /* Address of interface */   
     7     struct sockaddr *ifa_netmask; /* Netmask of interface */   
     8     union   
     9     {   
    10         struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */   
    11         struct sockaddr *ifu_dstaddr; /* Point-to-point destination address */   
    12     } ifa_ifu;   
    13     #define              ifa_broadaddr ifa_ifu.ifu_broadaddr   
    14     #define              ifa_dstaddr   ifa_ifu.ifu_dstaddr   
    15     void            *ifa_data;    /* Address-specific data */   
    16 };   

    ifa_next指向链表的下一个成员;ifa_name是接口名称,以0结尾的字符串,比如eth0,lo;ifa_flags是接口的标识位(比如当IFF_BROADCAST或IFF_POINTOPOINT设置到此标识位时,影响联合体变量ifu_broadaddr存储广播地址或ifu_dstaddr记录点对点地址);ifa_netmask存储该接口的子网掩码;结构体变量存储广播地址或点对点地址(见括弧介绍ifa_flags);ifa_data存储了该接口协议族的特殊信息,它通常是NULL(一般不关注他)。

        函数getifaddrs(int getifaddrs (struct ifaddrs **__ifap))获取本地网络接口信息,将之存储于链表中,链表头结点指针存储于__ifap中带回,函数执行成功返回0,失败返回-1,且为errno赋值。
        很显然,函数getifaddrs用于获取本机接口信息,比如最典型的获取本机IP地址。

  • 相关阅读:
    Android深度探索--第三章读后感
    Android深度探索--第二章读后感
    Android深度探索--第一章读后感
    android深度探索第十章心得体会
    android深度探索第九章心得体会
    android深度探索第八章心得体会
    深度探索android第七章
    Android 深度探索第六章
    深度探索android第五章
    Android深度探索第四章读后感
  • 原文地址:https://www.cnblogs.com/fnlingnzb-learner/p/6427388.html
Copyright © 2020-2023  润新知