在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