目录

设计思路

ioctl操作参数

获取网口的遍历结构

获取对应的参数信息

源代码

ifinfo.c

ifinfo.h

test.c

测试结果


设计思路

首先给需要查询的信息定义个结构(当然,这里可以扩展)

/***  struct ifinfo - 网卡信息结构*  *  if_idx  网口在系统中的索引,          这里需要注意的是,派生的网口 em1:1 与 em1 的索引相同*  if_name 网口名,例如:eth0*  if_flag 网口状态,参见 IFSTAT_XXX 宏定义*  if_ipv4 网口IP地址,例如:10.170.6.66*  if_eth.if_ethmac    网口MAC地址,格式:28:6E:D4:88:C7:9A*  if_eth.if_ethspeed  网口带宽,单位:Mbps*/
struct ifinfo {unsigned int if_idx;    //接口索引号char if_name[32];       //接口名 如:eth0int if_flag;
#define IFSTAT_UP           0x0001  /* 接口状态为 up */
#define IFSTAT_BROADCAST    0x0002  /* 广播地址可用 */
#define IFSTAT_LOOPBACK     0x0004  /* 该网口是回环口 */
#define IFSTAT_POINTOPOINT  0x0010  /* 点对点连接 */
#define IFSTAT_MULTICAST    0x0020  /* 支持多播 */char if_ipv4[16];       //接口IPv4地址struct {char if_ethmac[64];         //MAC地址unsigned int if_ethspeed;   //速率 Mbps}if_eth;
};

ioctl操作参数

才头文件 sys/sockios.h,linux/sockios.h 中定义了一些列的操作数

#include <sys/sockios.h>
#include <linux/sockios.h>#define SIOCGIFNAME 0x8910      /* get iface name       */
#define SIOCSIFLINK 0x8911      /* set iface channel        */
#define SIOCGIFCONF 0x8912      /* get iface list       */
#define SIOCGIFFLAGS    0x8913      /* get flags            */
#define SIOCSIFFLAGS    0x8914      /* set flags            */
#define SIOCGIFADDR 0x8915      /* get PA address       */
#define SIOCSIFADDR 0x8916      /* set PA address       */
#define SIOCGIFDSTADDR  0x8917      /* get remote PA address    */
#define SIOCSIFDSTADDR  0x8918      /* set remote PA address    */
#define SIOCGIFBRDADDR  0x8919      /* get broadcast PA address */
#define SIOCSIFBRDADDR  0x891a      /* set broadcast PA address */
#define SIOCGIFNETMASK  0x891b      /* get network PA mask      */
#define SIOCSIFNETMASK  0x891c      /* set network PA mask      */

获取网口的遍历结构

使用ioctl接口的SIOCGIFCONF选项,

/* 获取所有网口的句柄信息 */
static int get_ifconf_r(int sockfd, struct ifconf *ifc, void *buf, int buf_len)
{if(sockfd <= 2 || !ifc || !buf || buf_len <= 0) {return -1;}ifc->ifc_len = buf_len;ifc->ifc_buf = buf;if (ioctl(sockfd, SIOCGIFCONF, ifc) == -1) {return -1;}return 0;
}

获取对应的参数信息

使用ioctl接口的SIOCGIFADDR选项,

/* 查询网口 IPv4 地址 */
static int get_ifaddr(int sockfd, const char *if_name, char *addr, int addr_len)
{if(sockfd <= 2 || !if_name || !addr || addr_len <= 0) {return -1;}struct ifreq ifr;strcpy(ifr.ifr_name, if_name);if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) == 0) {if (ioctl(sockfd, SIOCGIFADDR, &ifr) == 0) {snprintf(addr,addr_len,"%s",inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr));}}else{return -1;}return 0;
}

源代码

GitHub地址:https://github.com/Rtoax/test/tree/master/nic/ifinfo

ifinfo.c

/***  获取网口信息,IP地址,MAC地址,状态,带宽等*  *  日期:2020年10月16日*  作者:RToax*/
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <linux/sockios.h>
#include <linux/ethtool.h>#include "ifinfo.h"/* 创建Socket */
static int if_socket()
{int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);if (sock == -1) {return -1;}return sock;
}/* 获取所有网口的句柄信息 */
static int get_ifconf_r(int sockfd, struct ifconf *ifc, void *buf, int buf_len)
{if(sockfd <= 2 || !ifc || !buf || buf_len <= 0) {return -1;}ifc->ifc_len = buf_len;ifc->ifc_buf = buf;if (ioctl(sockfd, SIOCGIFCONF, ifc) == -1) {return -1;}return 0;
}/* 获取网口状态 */
static int get_ifstat(int sockfd, const char *if_name, int *if_flag)
{if(sockfd <= 2 || !if_name || !if_flag) {return -1;}struct ifreq ifr;*if_flag = 0;strcpy(ifr.ifr_name, if_name);if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) == 0) {if(ifr.ifr_flags & IFF_UP) *if_flag |= IFSTAT_UP;if(ifr.ifr_flags & IFF_BROADCAST) *if_flag |= IFSTAT_BROADCAST;if(ifr.ifr_flags & IFF_LOOPBACK) *if_flag |= IFSTAT_LOOPBACK;if(ifr.ifr_flags & IFF_POINTOPOINT) *if_flag |= IFSTAT_POINTOPOINT;if(ifr.ifr_flags & IFF_MULTICAST) *if_flag |= IFSTAT_MULTICAST;}else{return -1;}return 0;
}/* 查询网口 IPv4 地址 */
static int get_ifaddr(int sockfd, const char *if_name, char *addr, int addr_len)
{if(sockfd <= 2 || !if_name || !addr || addr_len <= 0) {return -1;}struct ifreq ifr;strcpy(ifr.ifr_name, if_name);if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) == 0) {if (ioctl(sockfd, SIOCGIFADDR, &ifr) == 0) {snprintf(addr,addr_len,"%s",inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr));}}else{return -1;}return 0;
}/* 查询网口 MAC 地址 */
static int get_ifhwaddr(int sockfd, const char *if_name, char *hwaddr, int hwaddr_len)
{if(sockfd <= 2 || !if_name || !hwaddr || hwaddr_len <= 0) {return -1;}struct ifreq ifr;strcpy(ifr.ifr_name, if_name);if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) == 0) {unsigned char * ptr ;ptr = (unsigned char  *)&ifr.ifr_ifru.ifru_hwaddr.sa_data[0];snprintf(hwaddr,hwaddr_len,"%02X:%02X:%02X:%02X:%02X:%02X",*ptr,*(ptr+1),*(ptr+2),*(ptr+3),*(ptr+4),*(ptr+5));}else{return -1;}return 0;
}/* 查询网口带宽 */
static int get_ifethspeed(int sockfd, const char *if_name, unsigned int *speed)
{struct ifreq ifr;struct ethtool_cmd ep;strcpy(ifr.ifr_name, if_name);ep.cmd = ETHTOOL_GSET; ifr.ifr_data = (caddr_t)&ep;  if (ioctl(sockfd, SIOCETHTOOL, &ifr) != 0) { // 如果出错退出; return -1;}*speed = ep.speed;return 0;
}/***  get_ifinfo - 获取网口信息**    该接口可以获取网口的速率,但是,在虚拟机环境中,无法查询网口带宽*  *  display_fn  查询的回调函数,参见: ifinfo_display 说明*  arg         回调函数被调用时的 arg 参数,该参数可以为 NULL*  *  return      失败,返回 -1, 成功,返回查询的网口总数*/
int get_ifinfo(ifinfo_display display_fn, void *arg)
{/* 如果回调函数为空,则返回失败 */if(!display_fn) {return -1;}struct ifconf ifc;struct ifinfo info;char buf[2048];int ret = 0;    int count = 0;int sock = if_socket();/* 创建socket */ret = get_ifconf_r(sock, &ifc, buf, sizeof(buf));if(ret != 0) {close(sock);return -1;}/* 巧妙的网口结构保存 */struct ifreq* it = ifc.ifc_req;const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));/* 轮询所有网口 */for (; it != end; ++it, count++) {memset(&info, 0, sizeof(struct ifinfo));strcpy(info.if_name, it->ifr_name);info.if_idx = if_nametoindex(info.if_name);/* 获取一系列的网口信息,当然可以在后面继续开发,但不要忘记在 struct ifinfo 添加对应的单数字段 */get_ifstat(sock, info.if_name, &info.if_flag);get_ifaddr(sock, info.if_name, info.if_ipv4, sizeof(info.if_ipv4));get_ifhwaddr(sock, info.if_name, info.if_eth.if_ethmac, sizeof(info.if_eth.if_ethmac));get_ifethspeed(sock, info.if_name, &info.if_eth.if_ethspeed);/* 在这里,回调函数将被调用 */if(display_fn) display_fn(&info, arg);}close(sock);return count;
}

ifinfo.h

/***  获取网口信息,IP地址,MAC地址,状态,带宽等*  *  日期:2020年10月16日*  作者:RToax*/
#ifndef __IF_INFO_H
#define __IF_INFO_H 1/***  struct ifinfo - 网卡信息结构*  *  if_idx  网口在系统中的索引,          这里需要注意的是,派生的网口 em1:1 与 em1 的索引相同*  if_name 网口名,例如:eth0*  if_flag 网口状态,参见 IFSTAT_XXX 宏定义*  if_ipv4 网口IP地址,例如:10.170.6.66*  if_eth.if_ethmac    网口MAC地址,格式:28:6E:D4:88:C7:9A*  if_eth.if_ethspeed  网口带宽,单位:Mbps*/
struct ifinfo {unsigned int if_idx;    //接口索引号char if_name[32];       //接口名 如:eth0int if_flag;
#define IFSTAT_UP           0x0001  /* 接口状态为 up */
#define IFSTAT_BROADCAST    0x0002  /* 广播地址可用 */
#define IFSTAT_LOOPBACK     0x0004  /* 该网口是回环口 */
#define IFSTAT_POINTOPOINT  0x0010  /* 点对点连接 */
#define IFSTAT_MULTICAST    0x0020  /* 支持多播 */char if_ipv4[16];       //接口IPv4地址struct {char if_ethmac[64];         //MAC地址unsigned int if_ethspeed;   //速率 Mbps}if_eth;
};/***  ifinfo_display - 网口状态查询回调函数*  *  info    网口信息结构指针,参见: struct ifinfo 说明*  arg     调用 get_ifinfo 内存地址传入的 arg 地址指针*/
typedef void (*ifinfo_display)(const struct ifinfo *info, void *arg);/***  get_ifinfo - 获取网口信息**    该接口可以获取网口的速率,但是,在虚拟机环境中,无法查询网口带宽**  display_fn  查询的回调函数,参见: ifinfo_display 说明*  arg         回调函数被调用时的 arg 参数,该参数可以为 NULL*  *  return      失败,返回 -1, 成功,返回查询的网口总数*/
int get_ifinfo(ifinfo_display display_fn, void *arg);#endif /*<__IF_INFO_H>*/

test.c


#include <stdio.h>#include "ifinfo.h"void ifdisplay(const struct ifinfo *info, void *arg)
{printf("%2d: %-10s %16s %18s %d Mb \n",info->if_idx, info->if_name,info->if_ipv4, info->if_eth.if_ethmac,info->if_eth.if_ethspeed);
}int main()
{int ret = 0;while(1) {ret = get_ifinfo(ifdisplay, NULL);printf("Total %d interface.\n", ret);sleep(1);}
}

测试结果

在虚拟机中无法查询网口带宽

[root@localhost ifinfo]# make
gcc ifinfo.c test.c -o test.out
[root@localhost ifinfo]# ./test.out 1: lo                127.0.0.1  00:00:00:00:00:00 0 Mb 2: eth0            10.170.6.66  28:6E:D4:88:C7:9A 0 Mb 5: docker0          172.17.0.1  02:42:57:6F:10:40 0 Mb
Total 3 interface.用ifconfig查询的结果
-----------------------------------
[root@localhost ifinfo]# ifconfig -a
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255ether 02:42:57:6f:10:40  txqueuelen 0  (Ethernet)RX packets 0  bytes 0 (0.0 B)RX errors 0  dropped 0  overruns 0  frame 0TX packets 0  bytes 0 (0.0 B)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500inet 10.170.6.66  netmask 255.255.255.0  broadcast 10.170.6.255inet6 fe80::2731:24c7:9924:2028  prefixlen 64  scopeid 0x20<link>inet6 fe80::4b76:dca0:14ca:2d95  prefixlen 64  scopeid 0x20<link>inet6 fe80::cb30:c5c4:34dd:895f  prefixlen 64  scopeid 0x20<link>ether 28:6e:d4:88:c7:9a  txqueuelen 1000  (Ethernet)RX packets 3347634794  bytes 2727102880807 (2.4 TiB)RX errors 0  dropped 0  overruns 0  frame 0TX packets 43937802  bytes 187858063132 (174.9 GiB)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536inet 127.0.0.1  netmask 255.0.0.0inet6 ::1  prefixlen 128  scopeid 0x10<host>loop  txqueuelen 1000  (Local Loopback)RX packets 888190  bytes 13054543624 (12.1 GiB)RX errors 0  dropped 0  overruns 0  frame 0TX packets 888190  bytes 13054543624 (12.1 GiB)TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

这里介绍一个工具《Linux查看网口带宽状态(ifconfig,netstat,ethtool)》,该工具的:github地址。

[root@localhost ifstatus]# ./ifstatus.sh Name   Speed   Status  docker0     Unknown!    downeth0    Unknown!    uplo    Unknown!    up

在真实的物理服务器上运行结果为

[root@localhost rtoax]# ./test.out 1: lo                127.0.0.1  00:00:00:00:00:00 0 Mb 2: em1            10.170.7.166  20:04:0F:FA:87:3C 1000 Mb 2: em1:1          10.170.7.183  20:04:0F:FA:87:3C 1000 Mb 2: em1:2          10.170.7.184  20:04:0F:FA:87:3C 1000 Mb 2: em1:3          10.170.7.185  20:04:0F:FA:87:3C 1000 Mb 2: em1:4          10.170.7.186  20:04:0F:FA:87:3C 1000 Mb 2: em1:5          10.170.7.187  20:04:0F:FA:87:3C 1000 Mb 2: em1:6          10.170.7.188  20:04:0F:FA:87:3C 1000 Mb 2: em1:7          10.170.7.189  20:04:0F:FA:87:3C 1000 Mb 2: em1:8          10.170.7.190  20:04:0F:FA:87:3C 1000 Mb 2: em1:9          10.170.7.191  20:04:0F:FA:87:3C 1000 Mb 2: em1:10         10.170.7.192  20:04:0F:FA:87:3C 1000 Mb 3: em2            10.171.7.166  20:04:0F:FA:87:3D 65535 Mb 7: virbr0        192.168.122.1  52:54:00:9F:56:64 0 Mb
Total 14 interface.

Linux系统利用C语言获取网口信息(IP地址,MAC地址,状态,带宽speed等)相关推荐

  1. Linux服务器配置网络,可修改服务器Ip与Mac地址

    在服务器的网络配置中,需要同时配置这两种网络,才能使服务器正常使用.使用内网是为了保证我们的服务器处在一个安全的网络环境中,可以减少外部病毒的影响,而访问外网是为了方便我们配置服务器一些资源,如驱动程 ...

  2. C语言获取硬件信息(CPU序列号,硬盘序列号,网卡IP、MAC地址、是否插入网线)

    目录 一.前言 二.代码实现 2.1 获取CPU序列号 2.2 获取硬盘序列号 2.3 获取网卡信息 附:源代码下载 一.前言   本文主要介绍Linux和Windows下使用C语言获取各种硬件信息, ...

  3. Linux系统下怎么查询自己的ip和port

    Linux系统下如何查询自己的ip和port 前言:在Linux系统中,学习网络协议之后,就需要经常查看自己系统的ip和port是否正常开启,那么怎么快速查找它们呢? 我现在就把它们列出来,以解我的心 ...

  4. 在Linux上利用python获取本机ip

    下面介绍在Linux上利用python获取本机ip的方法. 经过网上调查, 发现大致有两种方法, 一种是调用shell脚本,另一种是利用python中的socket等模块来得到,下面是这两种方法的源码 ...

  5. linux多cpu运行python脚本,linux系统使用python获取cpu信息脚本分享

    linux系统使用python获取cpu信息脚本分享 代码如下: #!/usr/bin/env Python from __future__ import print_function from co ...

  6. Linux系统查看FC HBA卡信息的方法

    Linux系统查看FC HBA卡信息的方法 转载:地址我忘了 一.Windows 系统 在Windows系统中,可以使用FC HBA卡厂家提供的管理软件查看光纤适配器的WWN号码,具体如下: Qlog ...

  7. Linux系统站群VPS增加多IP绑定的详细教程、VPS额外增加IP手动绑定

    Linux系统站群VPS增加多IP绑定的详细教程.VPS额外增加IP手动绑定 我们购买的VPS如果有多个IP就需要手动绑定了,确定我们购买成功之后,我们需要编辑文件了. 文件目录/etc/syscon ...

  8. linux绑定ip mac地址,人文网-Linux系统绑定IP和MAC地址

    一.ARP欺骗病毒,主要表现为: 中病毒的机器不仅影响自身,同时也会影响同网段的其它机器,将其它机器的HTTP数据包里加入病毒代码. 代码例子如: 这种病毒危害非常大!即使你机器的安全性做得很好,可是 ...

  9. 属于Linux下的编辑器,vi编辑器是所有linux系统下标准的编辑器,它可分为哪些状态?()...

    vi编辑器是所有linux系统下标准的编辑器,它可分为哪些状态?() 更多相关问题 [单选题]2.三角形的三个内角之和是( )度 A. 180 B. 160 C. 170 D. 150 [单选题]下图 ...

最新文章

  1. Matlab与线性代数 -- 显示格式的设置
  2. SharePoint 2010 change home page或者default page
  3. php csv 简单的导入
  4. MYSQL 时间计算的 3 种函数
  5. 脑裂问题解决方案_从解决方案到问题
  6. Python 程序 可以一直输入 quit_从零开始学Python - 第002课:第一个Python程序
  7. 去哪儿-21-debuggiing-testing
  8. 解释器模式 Interpreter
  9. android 好用的工具,android studio 的几个好用的工具
  10. python 内存溢出能捕获吗_Python内存泄漏和内存溢出的解决方案
  11. 22.Windows及linux下gerapy使用
  12. java退出函数_如何更新线上的 Java 服务器代码
  13. 学科前沿技术专题第九章
  14. eclipse新建JSP页面报错:Multiple annotations found at this line解决方法
  15. 脑卒中后认知障碍的现代康复治疗进展
  16. redis set设置有效时间问题
  17. 并发编程——Hook线程
  18. 使用代理后,雷鸟连接qq邮箱
  19. python程序设计基础教程骆焦煌答案_清华大学出版社-图书详情-《C语言程序设计教程》...
  20. 计算机网络:IP地址

热门文章

  1. linux sshd进程起不来,linux sshd服务异常
  2. java配置springmvc_告别XML 使用JAVA配置SpringMVC
  3. Java并发编程-ReadWriteLock读写锁
  4. 人工智能实战_第八次作业_手写数学式子识别_廖盈嘉
  5. 网络编程基础_5.3聊天室-多人聊天室
  6. Tesseract-OCR的简单使用与训练
  7. XPath 轴 Axes
  8. jQuery 插件写法
  9. newton法分形图
  10. WPF 中出现不同线程间操作的解决