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語言代碼實現。socket

 

 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(通常不關注他)。this

    函數getifaddrs(int getifaddrs (struct ifaddrs **__ifap))獲取本地網絡接口信息,將之存儲於鏈表中,鏈表頭結點指針存儲於__ifap中帶回,函數執行成功返回0,失敗返回-1,且爲errno賦值。
    很顯然,函數getifaddrs用於獲取本機接口信息,好比最典型的獲取本機IP地址。spa

相關文章
相關標籤/搜索