1. 获取接口其它信息
前面我们已经了解了 ioctl 的使用方法,现在我们希望获取更多的接口信息,最后将其封装成一个独立函数,名为 getIfiInfo.
我们先来看看这个函数的演示示例,后面再给出详细过程。getIfiInfo 获取所有接口的配置信息,并保存在数组 ifi 中。该函数返回值是数组大小,也就是接口的个数。
图1 getIfiInfo 函数使用示例
上面的程序只是获取了接口信息,并将所有接口信息输出到了屏幕。经过编译运行后,结果如图 2 所示。
图2 getIfiInfo 获取到的接口信息
我们的目的就是写出 getIfiInfo 这个函数。
所有代码托管在:http://git.oschina.net/ivan_allen/unp
本文程序路径:unp/program/interface/getifinfo
2. ioctl 接口相关的其他命令
从图 2 中我们看到打印的信息有:
- 接口功能,即标志位
- 接口索引号
- MTU
- MAC 地址
- 配置的 IP 地址
- 子网掩码
- 广播地址
每一个信息都需要通过 ioctl 函数来获取,有点麻烦,这也是封装 getIfiInfo 的初衷。
下表列举了操作接口的常用的 ioctl 命令:
命令 | 说明 | 数据类型 |
---|---|---|
SIOCGIFCONF, SIOCSIFCONF | 获取,设置所有接口列表 | struct ifconf |
SIOCGIFADDR, SIOCSIFADDR | 获取,设置接口地址 | struct ifreq |
SIOCGIFINDEX | 获取接口索引号 | struct ifreq |
SIOCGIFFLAGS, SIOCSIFFLAGS | 获取,设置接口标志 | struct ifreq |
SIOCGIFMTU, SIOCSIFMTU | 获取,设置接口 MTU | struct ifreq |
SIOCGIFDSTADDR, SIOCSIFDSTADDR | 获取,设置P2P地址 | struct ifreq |
SIOCGIFBRDADDR, SIOCSIFBRDADDR | 获取,设置广播地址 | struct ifreq |
SIOCGIFNETMASK, SIOCSIFNETMASK | 获取,设置子网掩码 | struct ifreq |
SIOCGIFMETRIC, SIOCSIFMETRIC | 获取,设置接口管理距离 | struct ifreq |
SIOCGIFHWADDR, SIOCSIFHWADDR | 获取,设置接口 MAC 地址 | struct ifreq |
3. 封装 getIfiInfo 函数
首先需要定义一个新的结构体,如下:
struct ifi_info { char ifi_name[IFI_NAMESIZE]; // 接口名称 16 字节 short ifi_index; // 接口索引 short ifi_mtu; // 接口 MTU unsigned char ifi_haddr[IFI_HADDRSIZE]; // 物理地址 8 字节 unsigned short ifi_hlen; // 物理地址长度 short ifi_flags; struct sockaddr *ifi_addr; // 主地址 struct sockaddr *ifi_netmask; // 子网掩码 struct sockaddr *ifi_brdaddr; // 广播地址 struct sockaddr *ifi_dstaddr; // 目标地址 };
接下来,定义 getIfiInfo 函数:
// 该函数通过参数返回一个struct ifi_info 类型数组地址,将地址保存在 ifi 中。 // 返回值:数组大小 int getIfiInfo(struct ifi_info **ifi);
我不打算把 getIfiInfo 函数的完整代码贴在这里,想要看完整代码,可以在 unp/program/util/common.cc
这个文件中找到它。这里我以获取接口 mac 地址为例:
int getIfiInfo(struct ifi_info **ifi) { struct ifi_info *_ifi = malloc(/*...*/); // ... struct ifreq ifrcopy; // 给 ifrcopy 填充接口名称。 // 获取 mac 地址 ret = ioctl(sockfd, SIOCGIFHWADDR, &ifrcopy); if (ret < 0) ERR_EXIT("ioctl"); // 将 mac 地址保存到申请的内存中去 memcpy(_ifi[k].ifi_haddr, ((struct sockaddr*)&ifrcopy.ifr_hwaddr)->sa_data, 6); _ifi[k].ifi_hlen = 6; // ... *ifi = _ifi; return count; }
4. 总结
- 掌握获取接口配置的方法