GetNetState.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /**
  2. * 获取网口信息,IP地址,MAC地址,状态,带宽等
  3. *
  4. * 日期:2020年10月16日
  5. * 作者:RToax
  6. */
  7. #ifndef __IF_INFO_H
  8. #define __IF_INFO_H 1
  9. /**
  10. * struct ifinfo - 网卡信息结构
  11. *
  12. * if_idx 网口在系统中的索引, 这里需要注意的是,派生的网口 em1:1 与 em1 的索引相同
  13. * if_name 网口名,例如:eth0
  14. * if_flag 网口状态,参见 IFSTAT_XXX 宏定义
  15. * if_ipv4 网口IP地址,例如:10.170.6.66
  16. * if_eth.if_ethmac 网口MAC地址,格式:28:6E:D4:88:C7:9A
  17. * if_eth.if_ethspeed 网口带宽,单位:Mbps
  18. */
  19. struct ifinfo {
  20. unsigned int if_idx; //接口索引号
  21. char if_name[32]; //接口名 如:eth0
  22. int if_flag;
  23. #define IFSTAT_UP 0x0001 /* 接口状态为 up */
  24. #define IFSTAT_BROADCAST 0x0002 /* 广播地址可用 */
  25. #define IFSTAT_LOOPBACK 0x0004 /* 该网口是回环口 */
  26. #define IFSTAT_POINTOPOINT 0x0010 /* 点对点连接 */
  27. #define IFSTAT_MULTICAST 0x0020 /* 支持多播 */
  28. char if_ipv4[16]; //接口IPv4地址
  29. struct {
  30. char if_ethmac[64]; //MAC地址
  31. unsigned int if_ethspeed; //速率 Mbps
  32. }if_eth;
  33. };
  34. /**
  35. * ifinfo_display - 网口状态查询回调函数
  36. *
  37. * info 网口信息结构指针,参见: struct ifinfo 说明
  38. * arg 调用 get_ifinfo 内存地址传入的 arg 地址指针
  39. */
  40. typedef void (*ifinfo_display)(const struct ifinfo* info, void* arg);
  41. /**
  42. * get_ifinfo - 获取网口信息
  43. *
  44. * 该接口可以获取网口的速率,但是,在虚拟机环境中,无法查询网口带宽
  45. *
  46. * display_fn 查询的回调函数,参见: ifinfo_display 说明
  47. * arg 回调函数被调用时的 arg 参数,该参数可以为 NULL
  48. *
  49. * return 失败,返回 -1, 成功,返回查询的网口总数
  50. */
  51. int get_ifinfo(ifinfo_display display_fn, void* arg);
  52. /**
  53. * 获取网口信息,IP地址,MAC地址,状态,带宽等
  54. *
  55. * 日期:2020年10月16日
  56. * 作者:RToax
  57. */
  58. #include <unistd.h>
  59. #include <string.h>
  60. #include <stdio.h>
  61. #include <netinet/in.h>
  62. #include <net/if.h>
  63. #include <sys/ioctl.h>
  64. #include <arpa/inet.h>
  65. #include <linux/sockios.h>
  66. #include <linux/ethtool.h>
  67. /* 创建Socket !!!使用完成一定要close 不关闭会导致too many open files */
  68. static int if_socket()
  69. {
  70. int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
  71. if (sock == -1) {
  72. return -1;
  73. }
  74. return sock;
  75. }
  76. /* 获取所有网口的句柄信息 */
  77. static int get_ifconf_r(int sockfd, struct ifconf* ifc, void* buf, int buf_len)
  78. {
  79. if (sockfd <= 2 || !ifc || !buf || buf_len <= 0) {
  80. return -1;
  81. }
  82. ifc->ifc_len = buf_len;
  83. ifc->ifc_buf = (char*)buf;
  84. if (ioctl(sockfd, SIOCGIFCONF, ifc) == -1) {
  85. return -1;
  86. }
  87. return 0;
  88. }
  89. /* 获取网口状态 */
  90. static int get_ifstat(int sockfd, const char* if_name, int* if_flag)
  91. {
  92. if (sockfd <= 2 || !if_name || !if_flag) {
  93. return -1;
  94. }
  95. struct ifreq ifr;
  96. *if_flag = 0;
  97. strcpy(ifr.ifr_name, if_name);
  98. if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) == 0) {
  99. if (ifr.ifr_flags & IFF_UP) *if_flag |= IFSTAT_UP;
  100. if (ifr.ifr_flags & IFF_BROADCAST) *if_flag |= IFSTAT_BROADCAST;
  101. if (ifr.ifr_flags & IFF_LOOPBACK) *if_flag |= IFSTAT_LOOPBACK;
  102. if (ifr.ifr_flags & IFF_POINTOPOINT) *if_flag |= IFSTAT_POINTOPOINT;
  103. if (ifr.ifr_flags & IFF_MULTICAST) *if_flag |= IFSTAT_MULTICAST;
  104. }
  105. else {
  106. return -1;
  107. }
  108. return 0;
  109. }
  110. /* 查询网口 IPv4 地址 */
  111. static int get_ifaddr(int sockfd, const char* if_name, char* addr, int addr_len)
  112. {
  113. if (sockfd <= 2 || !if_name || !addr || addr_len <= 0) {
  114. return -1;
  115. }
  116. struct ifreq ifr;
  117. strcpy(ifr.ifr_name, if_name);
  118. if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) == 0) {
  119. if (ioctl(sockfd, SIOCGIFADDR, &ifr) == 0) {
  120. snprintf(addr, addr_len, "%s",
  121. inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr));
  122. }
  123. }
  124. else {
  125. return -1;
  126. }
  127. return 0;
  128. }
  129. /* 查询网口 MAC 地址 */
  130. static int get_ifhwaddr(int sockfd, const char* if_name, char* hwaddr, int hwaddr_len)
  131. {
  132. if (sockfd <= 2 || !if_name || !hwaddr || hwaddr_len <= 0) {
  133. return -1;
  134. }
  135. struct ifreq ifr;
  136. strcpy(ifr.ifr_name, if_name);
  137. if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) == 0) {
  138. unsigned char* ptr;
  139. ptr = (unsigned char*)&ifr.ifr_ifru.ifru_hwaddr.sa_data[0];
  140. snprintf(hwaddr, hwaddr_len, "%02X:%02X:%02X:%02X:%02X:%02X",
  141. *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3), *(ptr + 4), *(ptr + 5));
  142. }
  143. else {
  144. return -1;
  145. }
  146. return 0;
  147. }
  148. static int get_ifnetMask(int sockfd, const char* if_name, char* netMask, int netMask_len)
  149. {
  150. if (sockfd <= 2 || !if_name || !netMask || netMask_len <= 0) {
  151. return -1;
  152. }
  153. struct ifreq ifr;
  154. strcpy(ifr.ifr_name, if_name);
  155. if (ioctl(sockfd, SIOCGIFNETMASK, &ifr) == 0) {
  156. snprintf(netMask, netMask_len, "%s",
  157. inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr));
  158. }
  159. else {
  160. return -1;
  161. }
  162. return 0;
  163. }
  164. /* 查询网口带宽 */
  165. static int get_ifethspeed(int sockfd, const char* if_name, unsigned int* speed)
  166. {
  167. struct ifreq ifr;
  168. struct ethtool_cmd ep;
  169. strcpy(ifr.ifr_name, if_name);
  170. ep.cmd = ETHTOOL_GSET;
  171. ifr.ifr_data = (caddr_t)&ep;
  172. if (ioctl(sockfd, SIOCETHTOOL, &ifr) != 0) { // 如果出错退出;
  173. return -1;
  174. }
  175. *speed = ep.speed;
  176. return 0;
  177. }
  178. /**
  179. * get_ifinfo - 获取网口信息
  180. *
  181. * 该接口可以获取网口的速率,但是,在虚拟机环境中,无法查询网口带宽
  182. *
  183. * display_fn 查询的回调函数,参见: ifinfo_display 说明
  184. * arg 回调函数被调用时的 arg 参数,该参数可以为 NULL
  185. *
  186. * return 失败,返回 -1, 成功,返回查询的网口总数
  187. */
  188. int get_ifinfo(ifinfo_display display_fn, void* arg)
  189. {
  190. /* 如果回调函数为空,则返回失败 */
  191. if (!display_fn) {
  192. return -1;
  193. }
  194. struct ifconf ifc;
  195. struct ifinfo info;
  196. char buf[2048];
  197. int ret = 0;
  198. int count = 0;
  199. int sock = if_socket();/* 创建socket */
  200. ret = get_ifconf_r(sock, &ifc, buf, sizeof(buf));
  201. if (ret != 0) {
  202. close(sock);
  203. return -1;
  204. }
  205. /* 巧妙的网口结构保存 */
  206. struct ifreq* it = ifc.ifc_req;
  207. const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
  208. /* 轮询所有网口 */
  209. for (; it != end; ++it, count++) {
  210. memset(&info, 0, sizeof(struct ifinfo));
  211. strcpy(info.if_name, it->ifr_name);
  212. info.if_idx = if_nametoindex(info.if_name);
  213. /* 获取一系列的网口信息,当然可以在后面继续开发,
  214. 但不要忘记在 struct ifinfo 添加对应的单数字段 */
  215. get_ifstat(sock, info.if_name, &info.if_flag);
  216. get_ifaddr(sock, info.if_name, info.if_ipv4, sizeof(info.if_ipv4));
  217. get_ifhwaddr(sock, info.if_name, info.if_eth.if_ethmac, sizeof(info.if_eth.if_ethmac));
  218. get_ifethspeed(sock, info.if_name, &info.if_eth.if_ethspeed);
  219. /* 在这里,回调函数将被调用 */
  220. if (display_fn) display_fn(&info, arg);
  221. }
  222. close(sock);
  223. return count;
  224. }
  225. #endif /*<__IF_INFO_H>*/