1.介绍
Linux网络程序与内核交互的方法是经过ioctl来实现的,ioctl与网络协议栈进行交互,可获得网络接口的信息,网卡设备的映射属性和配置网络接口.而且还可以查看,修改,删除ARP高速缓存的信息,因此,咱们有必要了解一下ioctl函数的具体实现.编程
2.函数说明
SYNOPSIS
#include <sys/ioctl.h>
int ioctl(int d, int request, ...);
DESCRIPTION
The ioctl() function manipulates the underlying device parameters of
special files. In particular, many operating characteristics of char-
acter special files (e.g., terminals) may be controlled with ioctl()
requests. The argument d must be an open file descriptor.
The second argument is a device-dependent request code. The third
argument is an untyped pointer to memory. It’s traditionally char
*argp (from the days before void * was valid C), and will be so named
for this discussion.
An ioctl() request has encoded in it whether the argument is an in
parameter or out parameter, and the size of the argument argp in bytes.
Macros and defines used in specifying an ioctl() request are located in
the file <sys/ioctl.h>.
RETURN VALUE
Usually, on success zero is returned. A few ioctl() requests use the
return value as an output parameter and return a non-negative value on
success. On error, -1 is returned, and errno is set appropriately.
数组
3.参数说明
类别缓存 |
Request网络 |
说明数据结构 |
数据类型app |
套框架 接异步 口 |
SIOCATMARK SIOCSPGRP SIOCGPGRP |
是否位于带外标记 设置套接口的进程ID或进程组ID 获取套接口的进程ID或进程组ID |
int int int |
文 件 |
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 |
ARP |
SIOCSARP SIOCGARP SIOCDARP |
建立/修改ARP表项 获取ARP表项 删除ARP表项 |
struct arpreq struct arpreq struct arpreq |
路 由 |
SIOCADDRT SIOCDELRT |
增长路径 删除路径 |
struct rtentry struct rtentry |
流 |
I_xxx |
|
|
4.相关数据结构
- <h2><a name="t4"></a>(1)网络接口请求结构ifreq</h2>
- struct ifreq {
- #define IFHWADDRLEN 6 //6个字节的硬件地址,即MAC
- union {
- char ifrn_name[IFNAMESIZ];
- }ifr_ifrn;
- union {
- struct sockaddr ifru_addr;
- struct sockaddr ifru_dstaddr;
- struct sockaddr ifru_broadaddr;
- struct sockaddr ifru_netmask;
- struct sockaddr ifru_hwaddr;
- short ifru_flags;
- int ifru_ivalue;
- struct ifmap ifru_map;
- int ifru_mtu;
- char ifru_slave[IFNAMSIZ];
- char ifru_newname[IFNAMSIZE];
- void __user* ifru_data;
- struct if_settings ifru_settings;
- }ifr_ifru;
- }
- #define ifr_name ifr_ifrn.ifrn_name;//接口名称
- #define ifr_hwaddr ifr_ifru.ifru_hwaddr;//MAC
- #define ifr_addr ifr_ifru.ifru_addr;//本地IP
- #define ifr_dstaddr ifr_ifru.dstaddr;//目标IP
- #define ifr_broadaddr ifr_ifru.broadaddr;//广播IP
- #define ifr_netmask ifr_ifru.ifru_netmask;//子网掩码
- #define ifr_flags ifr_ifru.ifru_flags;//标志
- #define ifr_metric ifr_ifru.ifru_ivalue;//接口侧度
- #define ifr_mtu ifr_ifru.ifru_mtu;//最大传输单元
- #define ifr_map ifr_ifru.ifru_map;//设备地址映射
- #define ifr_slave ifr_ifru.ifru_slave;//副设备
- #define ifr_data ifr_ifru.ifru_data;//接口使用
- #define ifr_ifrindex ifr_ifru.ifru_ivalue;//网络接口序号
- #define ifr_bandwidth ifr_ifru.ifru_ivalue;//链接带宽
- #define ifr_qlen ifr_ifru.ifru_ivalue;//传输单元长度
- #define ifr_newname ifr_ifru.ifru_newname;//新名称
- #define ifr_seeting ifr_ifru.ifru_settings;//设备协议设置
- 若是想得到网络接口的相关信息,就传入ifreq结构体.
-
- <h2><a name="t5"></a>(2)网卡设备属性ifmap</h2>
- struct ifmap {
- unsigned long mem_start;
- unsigned long mem_end;
- unsigned short base_addr;
- unsigned char irq;
- unsigned char dma;
- unsigned char port;
- }
-
- <h2><a name="t6"></a>(3)网络配置接口ifconf</h2>
- struct ifconf {
- int ifc_len;
- union {
- char__user *ifcu_buf;
- struct ifreq__user* ifcu_req;
- }ifc_ifcu;
- };
- #define ifc_buf ifc_ifcu.ifcu_buf;//缓冲区地址
- #define ifc_req ifc_ifcu.ifcu_req;//ifc_req地址
-
- <h2><a name="t7"></a>(4)ARP高速缓存操做arpreq</h2>
- /**
- ARP高速缓存操做,包含IP地址和硬件地址的映射表
- 操做ARP高速缓存的命令字 SIOCDARP,SIOCGARP,SIOCSARP分别是删除ARP高速缓存的一条记录,得到ARP高速缓存的一条记录和修改ARP高速缓存的一条记录
- struct arpreq{
- struct sockaddr arp_pa;
- struct sockaddr arp_ha;
- int arp_flags;
- struct sockaddr arp_netmask;
- char arp_dev[16];
- }
5. 相关代码例子
- <pre name="code" class="cpp">#include <sys/types.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
- #include <sys/socket.h>
- #include <netdb.h>
- #include <string.h>
- #include <fcntl.h>
- #include <net/if.h>
- #include <string.h>
-
- int main(int argc, char*argv[]) {
- int s,sv6;
- int err;
- s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- perror("socket error");
- return -1;
- }
-
-
- struct ifreq ifr;
- int ia = sizeof( struct ifreq );
- ia = sizeof(struct sockaddr);
- ia = 1; err = 0;
- bzero(&ifr, sizeof(struct ifreq));
- while (err != -1) {
-
- ifr.ifr_ifindex = ia++;
- err = ioctl(s, SIOCGIFNAME, &ifr);
- if (-1 == err) {
- perror("index error");
- } else {
- char ipbuf[255];
- inet_ntop(AF_INET,
- &((struct sockaddr_in*) &(ifr.ifr_ifru.ifru_addr))->sin_addr,
- ipbuf, sizeof(ipbuf));
- printf("the %dst interface is:%s \t addr:%s\n", ifr.ifr_ifindex,
- ifr.ifr_name, ipbuf);
- }
- }
-
- bzero(&ifr,sizeof(struct ifreq));
- memcpy(ifr.ifr_name, "eth0", 5);
- err = ioctl(s, SIOCGIFFLAGS, &ifr);
- if (!err) {
- printf("SIOCGIFFLAGS:%d\n", ifr.ifr_flags);
- }
-
-
- bzero(&ifr,sizeof(struct ifreq));
- memcpy(ifr.ifr_name, "eth0", 5);
- err = ioctl(s, SIOCGIFMTU, &ifr);
- if (err!=-1) {
- printf("SIOCGIFMTU:%d\n", ifr.ifr_mtu);
- }else
- perror("ioctl:");
-
- bzero(&ifr,sizeof(struct ifreq));
- memcpy(ifr.ifr_name, "eth0", 5);
-
- err = ioctl(s, SIOCGIFHWADDR, &ifr);
- if (-1!=err) {
- unsigned char* hw = ifr.ifr_ifru.ifru_hwaddr.sa_data;
- printf("SIOCGIFHWADDR:%02x:%02x:%02x:%02x:%02x:%02x\n", hw[0], hw[1],
- hw[2], hw[3], hw[4], hw[5]);
- }else
- perror("ioctl:");
-
-
- err = ioctl(s, SIOCGIFMAP, &ifr);
- if (!err) {
- printf(
- "SIOCGIFMAP,mem_start:%d,mem_end:%d,base_addr:%d,ifr_map:%d,dma:%d,port:%d\n",
- ifr.ifr_map.mem_start, ifr.ifr_map.mem_end,
- ifr.ifr_map.base_addr, ifr.ifr_map.irq, ifr.ifr_map.dma,
- ifr.ifr_map.port);
- }
-
- err = ioctl(s, SIOCGIFINDEX, &ifr);
- if (!err) {
- printf("SIOCGIFINDEX:%d\n", ifr.ifr_ifindex);
- }
-
- err = ioctl(s, SIOCGIFTXQLEN, &ifr);
- if (!err) {
- printf("SIOCGIFTXQLEN:%d\n", ifr.ifr_qlen);
- }
-
- bzero(&ifr,sizeof(struct ifreq));
- memcpy(ifr.ifr_name, "eth0", 5);
-
- struct sockaddr_in *sin = (struct sockaddr_in*) &ifr.ifr_addr;
- char ip[16];
- memset(ip, 0, 16);
- err = ioctl(s, SIOCGIFADDR, &ifr);
- if (!err) {
- inet_ntop(AF_INET, &sin->sin_addr.s_addr, ip, 16);
- printf("SIOCGIFADDR:%s\n", ip);
- }
-
-
-
- err = ioctl(s, SIOCGIFDSTADDR, &ifr);
- if (!err) {
- inet_ntop(AF_INET, &sin->sin_addr.s_addr, ip, 16);
- printf("SIOCGIFDSTADDR:%s\n", ip);
- }
-
- bzero(&ifr,sizeof(struct ifreq));
- memcpy(ifr.ifr_name, "eth0", 5);
- err = ioctl(s, SIOCGIFNETMASK, &ifr);
- if (!err) {
- inet_ntop(AF_INET, &sin->sin_addr.s_addr, ip, 16);
- printf("SIOCGIFNETMASK:%s\n", ip);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- memset(&ifr, 0, sizeof(ifr));
- memcpy(ifr.ifr_name, "eth0", 5);
- ioctl(s, SIOCGIFBRDADDR, &ifr);
- struct sockaddr_in *broadcast = (struct sockaddr_in*) &ifr.ifr_broadaddr;
-
- inet_ntop(AF_INET, &broadcast->sin_addr.s_addr, ip, 16);
- printf("BROADCAST IP:%s\n", ip);
- close(s);
- }
- </pre><br>
- <pre></pre>
- <br>
- <h1><a name="t9"></a>6.内核主要函数调用框架</h1>
- <p></p>
- <p>内核实现ioctl()函数的是sys_ioctl(),在内核中主要调用框架图以下,它清晰地给咱们展现ioctl的控制传递框架,咱们接下来的内容将根据此图向你们作详细的解释:</p>
- <p><img src="http://img.my.csdn.net/uploads/201211/26/1353937655_1774.jpg" alt=""><br>
- </p>
- <p><br>
- </p>
- <h1><a name="t10"></a>7.小结</h1>
- <p> 本文介绍了ioctrl 主要的用法,固然它还有不少用法,之后会继续追加的,该如函数的用法,主要就是其对应的request列表的用法,便是该函数的第二个参数的用法</p>
- <p><br>
- </p>
- <p>参考: UNIX 网络编程</p>
- <p><a href="http://blog.163.com/jlz_325/blog/static/19174000920126893245653/">http://blog.163.com/jlz_325/blog/static/19174000920126893245653/</a></p>
- <p><a href="http://www.linuxidc.com/Linux/2007-12/9680.htm">http://www.linuxidc.com/Linux/2007-12/9680.htm</a><br>
- </p>
- <p><a href="http://linux.chinaunix.net/techdoc/develop/2007/09/05/967137.shtml">http://linux.chinaunix.net/techdoc/develop/2007/09/05/967137.shtml</a><br>
- </p>
- <p><br>
- </p>