109-获取接口信息(一)

1. 接口的其他信息

上一篇文章简要的介绍了接口的名字和索引号的概念,我们也可以通过一些函数去获取、转换它们。可是,接口除了这些信息外,还有很多其它信息,比如接口上配置的 ip 地址啊,子网掩码啦,MTU 等等。

说了这么多,那要怎么才能获取到这些信息呢?有一个类似 fcntl 的函数,叫 ioctl,也是一个垃圾桶函数,通过不同命令来完成不同的功能。它的函数原型如下:

#include <unistd.h>
int ioctl(int fd, int request, ... /* void *arg */);

ioctl 不仅能操作接口,也能操作套接字,文件等等。它的命令非常非常多,根本数不过来,我们只能遇到一个学一个。

2. 获取所有接口信息

命令 SIOCGIFCONF,这个命令的意思是,Socket IOCtl Get InterFace Config,意思是用来获取接口配置。接口配置的数据类型是这样的(man netdevice):

struct ifconf {
    int                 ifc_len; /* 第二个成员的大小,value-result 参数 */
    union {
        char           *ifc_buf; /* buffer address */
        struct ifreq   *ifc_req; /* array of structures */
    };
};

第一个成员是一个 value-result 参数,你需要手工传递缓冲区大小给它。当 ioctl 函数返回时,也会修改这个成员,表示实际获取的数据长度。

第二个成员是一个联合体,我们比较关注的是 struct ifreq 这个类型,它样子如下:

struct ifreq {
    char ifr_name[IFNAMSIZ]; /* 接口名字,大小为 16 */
    union {
        struct sockaddr ifr_addr; // 接口配置的 IP 地址
        struct sockaddr ifr_dstaddr; // P2P 中对端地址
        struct sockaddr ifr_broadaddr; // 广播地址
        struct sockaddr ifr_netmask; // 子网掩码
        struct sockaddr ifr_hwaddr; // MAC 地址
        short           ifr_flags; // 标志位,用来指示网卡的功能
        int             ifr_ifindex; // 接口索引号
        int             ifr_metric; // 度量距离
        int             ifr_mtu; // MTU
        struct ifmap    ifr_map; // 接口硬件参数,后面的都不用管了
        char            ifr_slave[IFNAMSIZ]; 
        char            ifr_newname[IFNAMSIZ];
        char           *ifr_data;
    };
};

需要特别注意的是,struct ifreq 的第二个成员也是一个联合体。那么使用 ioctl 的 SIOCGIFCONF 获取的值,到底是该联合体中的哪个含义?

答:SIOCGIFCONF 获取的是接口配置的 IP 地址,即 ifr_addr.

这样一来,工作就简单多了,我们甚至可以把 struct ifreq 简化为:

struct ifreq {
    char ifr_name[IFNAMSIZ]; /* 接口名字,大小为 16 */
    struct sockaddr ifr_addr; // 接口配置的 IP 地址
};

说了这么多,来个例子实践一下。

3. 实例

通过 SIOCGIFCONF 命令获取所有接口配置。

  • 伪代码前半部分——获取接口配置
int sockfd;
char buf[4096];
struct ifconf ifc;

ifc.ifc_len = 4096;
ifc.ifc_buf = buf;

// 因为 ioctl 第一个参数是描述符,没办法,必须得传一个
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
// 获取接口配置
ioctl(sockfd, SIOCGIFCONF, &ifc);

// 之前我们说过,SIOCGIFCONF 是获取所有接口的配置,也就是说 ifconf 的第二个成员保存了所有的接口配置信息,是如何存储的?我们该如何遍历呢?

上面的程序写到一半,你拿到了 ifconf 的结果,但是你只知道 ifconf 的总长度,却不知道里面保存多少个接口的配置信息。看图 1,你就很容易明白,应该如何却遍历这里面的数据了。


这里写图片描述
图1

接着,我们尝试去遍历 ifconf 里的 ifreq 结构体,打印接口名字和配置的 IP 地址。

  • 伪代码后半部分——遍历
// 计算ifreq 的个数
int count = ifc.ifc_len / sizeof(struct ifreq);
struct ifreq *ifr = ifc.ifc_buf;
for (int i = 0; i < count; ++i) {
  printf("name = %s, ", ifr[i].ifr_name);
  printf("addr = %s\n", inet_ntoa(ifr[i].ifr_addr);
}

4. 实验

代码托管在:http://git.oschina.net/ivan_allen/unp
本文程序路径:unp/program/interface/ifconf


这里写图片描述
图2 运行结果

5. 总结

  • 掌握 struct ifconf 和 struct ifreq 结构体
  • 使用 ioctl 获取所有接口的配置

思考:在第 3 小节的实例中,使用了大小固定为 4096 的接收缓冲。如果使用 ioctl 获取数据,数据量非常有可能超过 4096,这时不就导致数据被截断了吗?你能解决这个问题吗?

注意:在 Linux 中,ioctl 数据被截断并不会返回错误,它什么都不会告诉你。
提示:在unp/program/util/common.cc 中,我将 ioctl 函数封装到了 getIfConf 中,你可以查看该函数的实现。

最后,到这里我们只学会了获取接口的名字和接口上配置的 IP,接口的子网掩码,MAC 地址等等这些我们都还不知道怎么获取,实际上也很简单,使用 ioctl 的其它命令就行,具体你可以使用 man netdevice 查看到,里头有非常非常多的命令让你去操作接口。不过在下一篇中,会介绍这些常用的接口操作命令。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值