翼辉系统获取网络信息
实际环境和特殊需求往往会将简单问题复杂化,比如计算机IP地址,对于一个连接中socket,可以直接获得本端和对端的IP、端口信息。
但在一些特殊场合我们可能需要更多的信息,比如系统中有几块网卡,他们的Mac地址是多少,每块网卡分配了几个IP(一个网卡对应多个IP)等等。
这些信息往往需要通过ifconfig指令来获得,对于程序员来说,在代码中调用外部的shell指令可不是个最佳方案,因为没人能保障不同平台、不同版本的ifconfig指令输出的格式是一致的。
ioctl函数没有纳入POXIS规范,各系统对ioctl的实现也不尽相同。
本篇文章中将介绍通过ioctl函数实现上述需求。
#include <sys/ioctl.h>
int ioctl(int fd, int request, … /* void *arg */);
返回:成功返回0,失败返回-1;
ioctl函数的参数只有3个,但却是Unix中少有的几个“家族类”复杂函数,这里摘录一段《Unix网络编程》一书中对ioctl函数的描述:
在传统上ioctl函数是用于那些普遍使用、但不适合归入其他类别的任何特殊的系统接口……网络程序(一般是服务器程序)中ioctl常用于在程序启动时获得主机上所有接口的信息:接口的地址、接口是否支持广播、是否支持多播,等等。
ioctl函数的第一个参数fd,可以表示一个打开的文件(文件句柄)或网络套接字,第二个和第三个参数体现了函数的家族特色,参数二request根据函数功能分类定义了多组宏,而参数三总是一个指针,指针的类型依赖于参数二request。因为ioctl的种类实在太多,这里只列出和本文相关的几个参数定义:

1、通过接口名称获取IP地址:
1 int get_ipstr(const char *ifname, char *ipstr) 2 { 3 int ret = -1; 4 register int fd; 5 struct ifreq ifr; 6 7 if (ipstr == NULL || ifname == NULL) { 8 return ret; 9 } 10 11 if (strlen(ifname) >= IFNAMSIZ) { 12 ret = -2; 13 return ret; 14 } 15 16 if ((fd = socket(AF_INET, SOCK_DGRAM, 0 )) > 0) { 17 strcpy(ifr.ifr_name, ifname); 18 if (!(ioctl(fd, SIOCGIFADDR, &ifr))) { 19 ret = 0; 20 strcpy(ipstr, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr)); 21 } 22 } 23 24 if (fd > 0) { 25 close(fd); 26 } 27 28 return ret; 29 }
2、打印网络接口信息:
1 int printf_ifinfo(void) 2 { 3 int fd; /* 套接字 */ 4 int if_len; /* 接口数量 */ 5 struct ifreq buf[IF_NAMESIZE]; /* ifreq结构数组 */ 6 struct ifconf ifc; /* ifconf结构 */ 7 8 /* 建立IPv4的UDP套接字fd */ 9 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 10 perror("socket(AF_INET, SOCK_DGRAM, 0)"); 11 return -1; 12 } 13 14 /* 初始化ifconf结构 */ 15 ifc.ifc_len = sizeof(buf); 16 ifc.ifc_buf = (caddr_t) buf; 17 18 /* 获得接口列表 */ 19 if (ioctl(fd, SIOCGIFCONF, (char *) &ifc) == -1) { 20 perror("SIOCGIFCONF ioctl"); 21 return -2; 22 } 23 24 /* 计算接口数量 */ 25 if_len = ifc.ifc_len / sizeof(struct ifreq); 26 printf("接口数量:%d\n", if_len); 27 28 /* 遍历每个接口 */ 29 while (if_len-- > 0) { 30 /* 打印接口名称 */ 31 printf("接口:%s\n", buf[if_len].ifr_name); 32 33 /* 获得接口标志 */ 34 if (!(ioctl(fd, SIOCGIFFLAGS, (char *) &buf[if_len]))) { 35 /* 接口状态 */ 36 if (buf[if_len].ifr_flags & IFF_UP) 37 { 38 printf("接口状态: UP\n"); 39 } else { 40 printf("接口状态: DOWN\n"); 41 } 42 } else { 43 char str[256]; 44 sprintf(str, "SIOCGIFFLAGS ioctl %s", buf[if_len].ifr_name); 45 perror(str); 46 } 47 48 /* IP地址 */ 49 if (!(ioctl(fd, SIOCGIFADDR, (char *) &buf[if_len]))) { 50 printf("IP地址:%s\n", (char*)inet_ntoa(((struct sockaddr_in*) (&buf[if_len].ifr_addr))->sin_addr)); 51 } else { 52 char str[256]; 53 sprintf(str, "SIOCGIFADDR ioctl %s", buf[if_len].ifr_name); 54 perror(str); 55 } 56 57 /* 子网掩码 */ 58 if (!(ioctl(fd, SIOCGIFNETMASK, (char *) &buf[if_len]))) { 59 printf("子网掩码:%s\n", (char*)inet_ntoa(((struct sockaddr_in*) (&buf[if_len].ifr_addr))->sin_addr)); 60 } else { 61 char str[256]; 62 sprintf(str, "SIOCGIFNETMASK ioctl %s", buf[if_len].ifr_name); 63 perror(str); 64 } 65 66 /* 广播地址 */ 67 if (!(ioctl(fd, SIOCGIFBRDADDR, (char *) &buf[if_len]))) { 68 printf("广播地址:%s\n", (char*)inet_ntoa(((struct sockaddr_in*) (&buf[if_len].ifr_addr))->sin_addr)); 69 } else { 70 char str[256]; 71 sprintf(str, "SIOCGIFBRDADDR ioctl %s", buf[if_len].ifr_name); 72 perror(str); 73 } 74 75 /*MAC地址 */ 76 if (!(ioctl(fd, SIOCGIFHWADDR, (char *) &buf[if_len]))) { 77 printf("MAC地址:%02x:%02x:%02x:%02x:%02x:%02x\n\n", 78 (unsigned char) buf[if_len].ifr_hwaddr.sa_data[0], 79 (unsigned char) buf[if_len].ifr_hwaddr.sa_data[1], 80 (unsigned char) buf[if_len].ifr_hwaddr.sa_data[2], 81 (unsigned char) buf[if_len].ifr_hwaddr.sa_data[3], 82 (unsigned char) buf[if_len].ifr_hwaddr.sa_data[4], 83 (unsigned char) buf[if_len].ifr_hwaddr.sa_data[5]); 84 } else { 85 char str[256]; 86 sprintf(str, "SIOCGIFHWADDR ioctl %s", buf[if_len].ifr_name); 87 perror(str); 88 } 89 } //–while end 90 91 /* 关闭socket */ 92 if (fd > 0) { 93 close(fd); 94 } 95 96 return 0; 97 }
3、相关数据结构:
1 /* net/if.h */ 2 struct ifconf 3 { 4 int ifc_len; /* Size of buffer. */ 5 union 6 { 7 __caddr_t ifcu_buf; 8 struct ifreq *ifcu_req; 9 } ifc_ifcu; 10 }; 11 12 struct ifreq 13 { 14 # define IFHWADDRLEN 6 15 # define IFNAMSIZ IF_NAMESIZE 16 17 union 18 { 19 char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */ 20 } ifr_ifrn; 21 22 union 23 { 24 struct sockaddr ifru_addr; 25 struct sockaddr ifru_dstaddr; 26 struct sockaddr ifru_broadaddr; 27 struct sockaddr ifru_netmask; 28 struct sockaddr ifru_hwaddr; 29 short int ifru_flags; 30 int ifru_ivalue; 31 int ifru_mtu; 32 struct ifmap ifru_map; 33 char ifru_slave[IFNAMSIZ]; /* Just fits the size */ 34 char ifru_newname[IFNAMSIZ]; 35 __caddr_t ifru_data; 36 } ifr_ifru; 37 };
4、参考资料:
1)、https://www.cnblogs.com/lidabo/category/431655.html
2)、https://blog.csdn.net/pengluer/category_715116.html
3)、https://blog.csdn.net/PenglueR/article/details/5793862
4)、https://blog.csdn.net/xiexingshishu/category_9263043.html
5)、https://www.cnblogs.com/tdyizhen1314/p/4896689.html
浙公网安备 33010602011771号