《Unix 网络编程》17:ioctl 操作
ioctl 操作

本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | contact@mails.ren | contact@mails.ren |
原文标题 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 |
原文地址 | https://www.cnblogs.com/lymtics/p/16366363.html | https://www.cnblogs.com/lymtics/p/16366363.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息

系列文章导航:《Unix 网络编程》笔记
概述

本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | contact@mails.ren | contact@mails.ren |
原文标题 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 |
原文地址 | https://www.cnblogs.com/lymtics/p/16366363.html | https://www.cnblogs.com/lymtics/p/16366363.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息

ioctl 简介
ioctl
函数传统上一直作为那些不适合归入其他精细定义类别的特性的系统接口- POSIX 在标准化过程中致力于创建一些特殊的函数以取代这个函数
- 尽管如此,与网络编程相关的、且依赖于实现的特性保留的 ioctl 请求仍不在少数,它们用于获取接口信息、访问路由表、访问 ARP 告诉缓存等等。
用于网络编程的 ioctl 命令可以划分为六类:
- 套接字操作(是否位于带外标记等)
- 文件操作(设置或清除非阻塞标志等)
- 接口操作(返回接口列表,获取广播地址等)
- ARP 表操作(创建、修改、获取或删除)
- 路由表操作(增加或删除)
- 流系统(第 31 章才会讲到)
ioctl 函数
本函数影响由 fd 参数引用的一个打开的文件,函数原型如下:
#include <unistd.h>
// 成功返回 0 出错返回 -1
int ioctl(int fd, int request, ... /* void arg */);
第三个参数总是一个指针,但是指针的类型依赖于 request 参数。
不但某些 ioctl 操作和某些 fcntl 操作功能重叠,而且某些操作可以使用 ioctl 以不止一种方式指定,如下:
类别 | Request | 说明 | 数据类型 |
---|---|---|---|
文件 | FIONBIN FIOASYNC FIONREAD FIOSETOWN FIOGETOWN |
设置/清除非阻塞I/O标志 设置/清除信号驱动异步I/O标志 获取接收缓存区中的字节数 设置文件的进程ID或进程组ID 获取文件的进程ID或进程组ID |
int int int int int |
接口 | SIOCGIFCONF SIOCSIFADDR SIOCGIFADDR SIOCSIFFLAGS SIOCGIFFLAGS SIOCSIFDSTADDR SIOCGIFDSTADDR SIOCGIFBRDADDR SIOCSIFBRDADDR SIOCGIFNETMASK SIOCSIFNETMASK SIOCGIFMETRIC SIOCSIFMETRIC SIOCGIFMTU SIOCxxx |
获取所有接口的清单 设置接口地址 获取接口地址 设置接口标志 获取接口标志 设置点到点地址 获取点到点地址 获取广播地址 设置广播地址 获取子网掩码 设置子网掩码 获取接口的测度 设置接口的测度 获取接口MTU (还有很多取决于系统的实现) |
struct ifconf struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq |
ARP | SIOCSARP SIOCGARP SIOCDARP |
创建/修改ARP表项 获取ARP表项 删除ARP表项 |
struct arpreq struct arpreq struct arpreq |
路由 | SIOCADDRT SIOCDELRT |
增加路径 删除路径 |
struct rtentry struct rtentry |
流 | I_xxx | 见 31 章 |
下面各节详细讲解这些请求。
注意:函数本身的返回值只能判断操作是否成功,下面都是通过第三个指针参数进行传递参数或获取返回值的!
套接字操作

本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | contact@mails.ren | contact@mails.ren |
原文标题 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 |
原文地址 | https://www.cnblogs.com/lymtics/p/16366363.html | https://www.cnblogs.com/lymtics/p/16366363.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息

这里,第三个参数指向一个 int 类型的变量
Request | 详细说明 | 代替 |
---|---|---|
SIOC.AT.MARK | 如果本套接字的读指针当前位于带外标记,则返回一个非 0 值,否则返回一个 0 值 | POSIX 以函数 sockatmark 替换本请求 |
SIOC.SP.GRP | 设置套接字的进程ID或进程组ID,该ID指定本套接字的 SIGIO 或 SIGURG 信号的接收进程 | fcntl 的 F_SET.OWN |
SIOC.GP.GRP | 返回本套接字的进程ID或组ID,该ID指定针对本套接字的SIGIO和SIGURG 信号的接收进程 | fcntl 的 F_GET.OWN |
文件操作

本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | contact@mails.ren | contact@mails.ren |
原文标题 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 |
原文地址 | https://www.cnblogs.com/lymtics/p/16366363.html | https://www.cnblogs.com/lymtics/p/16366363.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息

这一组请求以 FIO 打头,它们可能还适用于除了套接字外某些特定类型的文件。本节仅仅讨论适用于套接字的请求。
这里,第三个参数指向一个 int 类型的变量
Request | 详细说明 | 代替 |
---|---|---|
FIO.NBIO | 根据第三个参数(1或0),设置或清除本套接字的非阻塞IO标志 | 和 O_NON.BLOCK 文件标志状态等效可以通过 fcntl 的 F_SET.FL 清除或设置该标志 |
FIO.ASYNC | 根据第三个参数,设置或清除本套接字的信号驱动异步IO标志 决定是否受灾区针对本套接字的异步 IO 信号(SIGIO) |
和 O_ASYNC 文件标志状态等效可以通过 fcntl 的 F_SET.FL 清除或设置该标志 |
FIO.NREAD | 返回当前在本套接字接收缓冲区中的字节数 | |
FIO.SET.OWN | 对于套接字和 SIOC.SP.GRP 等效 |
|
FIO.GET.OWN | 对于套接字和 SIOC.GP.GRP 等效 |
接口操作

本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | contact@mails.ren | contact@mails.ren |
原文标题 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 |
原文地址 | https://www.cnblogs.com/lymtics/p/16366363.html | https://www.cnblogs.com/lymtics/p/16366363.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息

这里的接口(interface)指的就是网络接口;下文中的
IF
一般都是其缩写。
结构
许多需要处理网络接口的程序的初始步骤之一就是从内核获取配置在系统中的所有接口,这个任务由 SIGC.G.IFCONF
请求完成,并要借助于一个结构:ifconf
,而这个结构又包含了另一个结构 ifreq
。
我们在调用 ioctl 之前,要分配一个缓冲区和一个 ifconf 结构,然后初始化后者(如下图左侧),经过调用,该结构将被填充。
它们在调用前后的关系和变化如下:
下面是它们结构的代码:
get_ifi_info
目的:返回一个结构链表,每个结构对应一个处于 up 状态的接口
在原书中这段代码相当长,但是由于系统不一致等等原因,这段代码在我的机器上并不能如愿地运行起来,因此这里我只是看了一下代码的逻辑。下面部分只是对各个文件的功能做一个简述。
unpifi.h
头文件:
这个结构中保存了我们可能关注的信息,如接口名字、接口索引、MTU、硬件地址
prifinfo.c
作用:调用 get_ifi_info 函数(虽然我们还没有实现),并输出所有信息,可以看作是一个 mini 的 ifconfig 了
get_ifi_info.c
主要的逻辑部分,判断缓冲区大小是否足够(循环多次请求)、并根据相应的标志将数据保存到我们自定的结构中,最后还有一个用于释放空间的函数
操作
上面的 SIOC.G.IF.CONF
是获取每个已经配置的接口的名字和套接字地址结构,我们可以通过其他类似的请求以获取其他的信息。
get 通常由 netstat
程序发出,而 set 通常由 ifconfig
程序发出,后者需要超级用户权限。
request | 说明 | 数据类型 |
---|---|---|
SIOCGIFCONF | 获取所有接口的清单 | struct ifconf |
SIOCSIFADDR | 设置接口地址 | struct ifreq |
SIOCGIFADDR | 获取接口地址 | struct ifreq |
SIOCSIFFLAGS | 设置接口标志 | struct ifreq |
SIOCGIFFLAGS | 获取接口标志 | struct ifreq |
SIOCSIFDSTADDR | 设置点到点地址 | struct ifreq |
SIOCGIFDSTADDR | 获取点到点地址 | struct ifreq |
SIOCGIFBRDADDR | 获取广播地址 | struct ifreq |
SIOCSIFBRDADDR | 设置广播地址 | struct ifreq |
SIOCGIFNETMASK | 获取子网掩码 | struct ifreq |
SIOCSIFNETMASK | 设置子网掩码 | struct ifreq |
SIOCGIFMETRIC | 获取接口的测度 | struct ifreq |
SIOCSIFMETRIC | 设置接口的测度 | struct ifreq |
SIOCGIFMTU | 获取接口MTU | struct ifreq |
SIOCxxx | (还有很多取决于系统的实现) | struct ifreq |
ARP 高速缓存操作

本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | contact@mails.ren | contact@mails.ren |
原文标题 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 |
原文地址 | https://www.cnblogs.com/lymtics/p/16366363.html | https://www.cnblogs.com/lymtics/p/16366363.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息

介绍
ARP 高速缓存也通过 ioctl 函数操纵,但是使用路由套接字(下一章)的系统往往改用路由套接字访问 ARP 告诉缓存。一些较新的系统只支持用路由套接字执行这些 ARP 操作。
这些请求都使用如下的结构:
#include <net/if_arp.h>
struct arpreq {
struct sockaddr arp_pa; // 协议地址
struct sockaddr arp_ha; // 硬件地址
int arp_flags; // 标志位
}
#define ATF_INUSE 0x01 // 使用中
#define ATF_COM 0x02 // 已经完成
#define ATF_PERM 0x04 // 永久记录
#define ATF_PUBL 0x08 // 已发布
这里,第三个参数指向一个 arpreq 类型的变量
Request | 详细说明 |
---|---|
SIOC.S.ARP | 添加一个新的表项,或修改之; 其中 arp_pa 是一个含有 IP 地址的网络套接字地址结构 arp_ha 则是一个通用套接字地址结构,它的 sa_family 值为 AF_UNSPEC,sa_data 中含有硬件地址 ATF_PERM 和 ATF_PUBL 这两个标志也可以由应用程序指定 ATF_INUSE 和 ATF_COM 则由内核设置 |
SIOC.D.ARP | 从 ARP 高速缓冲删除一个表项,调用者指定要删除表项的网络地址 |
SIOC.G.ARP | 从 ARP 高速缓冲中获取一个表项,调用者指定网络地址,返回相应的硬件地址和标志 |
只有超级用户才能增加或删除表项,这三个请求通常由 arp 程序发出。
ioctl 没办法列出 ARP 高速缓存中的所有表项。当指定 -a 标志执行 arp 命令时,大多数版本的 arp 程序通过读取内核的内存 /dev/kmem
获得 ARP 告诉缓存的当前内容。下一章将用 sysctl 更容易地做到这一点。
代码
- 目标:输出主机的硬件地址
- 思路:使用上面的
get_ifi_info
函数返回一个主机的所有 IP 地址,然后对端每一个发送一个SIOC.G.ARP
请求以显示它的硬件地址
代码如下:
#include <net/if_arp.h>
#include "unpifi.h"
int main(int argc, char** argv) {
int sockfd;
struct ifi_info* ifi;
unsigned char* ptr;
struct arpreq arpreq;
struct sockaddr_in* sin;
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
// 调用 get_ifi_info 函数返回一个主机的所有 IP 地址
for (ifi = get_ifi_info(AF_INET, 0); ifi != NULL; ifi = ifi->ifi_next) {
// 使用 inet_ntop 显示 IP 地址
printf("%s: ", Sock_ntop(ifi->ifi_addr, sizeof(struct sockaddr_in)));
sin = (struct sockaddr_in*)&arpreq.arp_pa;
memcpy(sin, ifi->ifi_addr, sizeof(struct sockaddr_in));
// 然后对每一个 IP 地址发出一个 SIOCGARP 请求以获取他们的硬件地址
if (ioctl(sockfd, SIOCGARP, &arpreq) < 0) {
// 如果出错
err_ret("ioctl SIOCGARP");
continue;
}
// 打印信息
ptr = &arpreq.arp_ha.sa_data[0];
printf("%x:%x:%x:%x:%x:%x\n", *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3),
*(ptr + 4), *(ptr + 5));
}
exit(0);
}
路由表操作

本文信息 | 本文信息 | 防爬虫替换信息 |
---|---|---|
作者网站 | LYMTICS | https://lymtics.top |
作者 | LYMTICS(樵仙) | https://lymtics.top |
联系方式 | contact@mails.ren | contact@mails.ren |
原文标题 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 | 《Unix 网络编程》17:ioctl 操作 - 樵仙 - 博客园 |
原文地址 | https://www.cnblogs.com/lymtics/p/16366363.html | https://www.cnblogs.com/lymtics/p/16366363.html |
- 如果您看到了此内容,则本文可能是恶意爬取原作者的文章,建议返回原站阅读,谢谢您的支持
- 原文会不断地更新和完善,排版和样式会更加适合阅读,并且有相关配图
- 如果爬虫破坏了上述链接,可以访问 `lymtics.top` 获取更多信息

这里,第三个参数指向一个 rtentry 类型的变量
Request | 详细说明 | 代替 |
---|---|---|
SIOC.ADD.RT | 往路由表添加一个表项 | 和 O_NON.BLOCK 文件标志状态等效可以通过 fcntl 的 F_SET.FL 清除或设置该标志 |
SIOC.DEL.RT | 从路由表删除一个表项 |
这些请求通常由 route 程序发出,只有超级用户才能发出这些请求。
在支持路由域套接字的系统中,这些请求改由路由套接字而不是 ioctl 执行。
ioctl 没有办法列出路由表中的所有表项。这个操作通常由 netstat 程序在指定 -r 参数时完成。其通过读取内核的内存 /dev/kmem
获取整个路由表。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)