ioctl操作
在本书中有两个地方都对这个函数进行了介绍,其实还有很多地方需要这个函数。ioclt函数传统上一直作为纳西而不适合归入其他精细定义类别的特性的系统接口。网络程序(特别是服务器程序)经常在程序启动执行后使用ioctl获取所在主机全部网络接口的信心,包括:接口地址、是否支持广播、是否支持多播。
#include <unistd.h>
int ioctl(int fd,int request,...../* void *arg /);
//返回:若成功则为0.失败则我-1
- 套接字操作
- 文件操作
- 接口操作
- ARP高速缓存操作
- 路由表操作
- 流系统
不但某些ioclt操作和某些fcntl操作功能重叠(譬如把套接字设置为非阻塞),而且某些操作可以使用ioctl以不止一种方式制定(譬如设置套接字的进程组属主)。下表列出了网络相关ioctl请求的request参数以及arg地址必须指向的数据类型。

套接字操作
明确要求套接字ioctl请求有三个,它们都要求ioctl的第三个参数是指向某个整数的一个指针。
- SIOCATMARK:如果本套接字的读指针当前位于带外标记,那就通过由第三个参数指向的帧数放回一个非0值,否则返回一个0值。
- SIOCGPGRP:通过由第三个参数指向的整数返回本套接字的进程ID或进程组ID,该ID指定针对本套接字的SIGIO或SIGURG信号的接受进程。
- SIOCSPGR :本套接字的进程ID或进程组ID设置成由第三个参数指向的整数,该ID指定对本套接字的SIGIO或SIGURG信号的接受进程。
文件操作
以FIO打头的可能还适用于除套接字外某些特定类型的文件。都要求ioctl的第三个参数指向一个帧数。
- FIONBIO:根据ioctl的第三个参数指向一个0值或非0值,可消除或设置本套接字的非阻塞式I/O标志。本请求和O_NONBLOCK文件状态标志等效,而可以通过fcntlde F_SETFL命令清除或设置该标志。
- FIOASYNC:根据ioctl的第三个参数指向一个0值或非0值,可消除或设置本套接字的信号驱动异步I/O标志,它决定是否收取针对本套接字的异步I/O信号。本请求和O_ASYNC文件状态标志等效,而可以通过fcntl的F_SETFL命令清除或设置该标志
- FIONREAD:通过由ioctl的第三个参数指向的整数返回当前在本套接字接受缓冲区中的字节数。
- FIOSETOWN:对于本套接字和SIOCSPGRP等效
- FIOGETOWN:对于套接字和SIOCGPGRP等效。
接口配置
从内核获取配置在系统中的所有接口,由SIOCGIFCONF完成。它使用ifconf结构,ifconf又使用ifreq结构。在使用ioctl前先分配一个缓冲区和一个ifconf结构,然后初始化后者。假设缓冲区大小为1024字节,ioctl的第三个参数指向这个结构。
SIOCGIFCONF请求存在一个严重的问题是:在缓冲区大小不足以存放结果时,一些实现不返回错误,而是截断结果并返回成功(即ioctl的返回值为0)。要知道缓冲区足够大的唯一办法是:发请求,记下返回长度,用更大的缓冲区发请求,比较返回的长度和刚才记下的长度,只有这两个长度相同才说缓冲区足够大。
struct ifconf { //网络配置结构体是一种缓冲区
int ifc_len;//缓冲区ifr_buf的大小
union {
char__user *ifcu_buf; //绘冲区指针
struct ifreq__user* ifcu_req;//指向ifreq指针
}ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf;//缓冲区地址
#define ifc_req ifc_ifcu.ifcu_req;//ifc_req地址
#define IFNAMSIZ 16
struct ifreq {
#define IFHWADDRLEN 6 //6个字节的硬件地址,即MAC
union {
char ifrn_name[IFNAMESIZ]; //网络接口名称
}ifr_ifrn;
union {
struct sockaddr ifru_addr; //本地IP地址
struct sockaddr ifru_dstaddr;//目标IP地址
struct sockaddr ifru_broadaddr;//广播IP地址
struct sockaddr ifru_netmask;//本地子网掩码地址
struct sockaddr ifru_hwaddr;//本地MAC地址
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;//设备协议设置
使用SIOCGIFCONF前ifconf结构的初始化结果

SIOCGIFCONF返回值

接口操作
SIOCGIFCONF请求为每个已配置的接口返回其名字以及一个套接字地址结构。这些请求(get)版本(SIOCGxxx)由netstat程序发出。设置(set)版本(SIOCSxxx)由ifconfig发出。这些请求接受或返回一个ifreq结构中的信息。而这个结构的地址则作为ioctl调用的第三个参数指定。接口总是以其名字标识,在ifreq结构中的ifr_name指定,如;le0、lo0。
相关数据结构
ARP高速缓存
/*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[];//查询网络接口的名称
};
#define ATF_INUSE 0x01 //entry in use
#define ATF_COM 0x02//completed entry (hardware addr valid)
#define ATF_PERM 0x04//permanent entry
#define ATF_PUBL 0x08/published entry(respond for other host)
路有表操作
ioctl没有办法列出路有表中所有表项。这个操作通常有netstat程序在指定-r标志时完成。
//(2)网卡设备属性ifmap
struct ifmap { //网卡设备的映射属性
unsigned long mem_start;//开始地址
unsigned long mem_end;//结束地址
unsigned short base_addr;//基地址
unsigned char irq;//中断号
unsigned char dma;//DMA
unsigned char port;//端口
}
获取网络接口信息
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if.h>
#include <arpa/inet.h>
#include <linux/sockios.h>
/**
ioctl函数是与内核交互的一种方法,使用ioctl函数与内核协议栈进行交互
ioctl函数可操作I/O请求,文件请求与网络接口请求
网络接口请求的几个结构体:
struct ifreq{
#define IFHWADDRLEN 6 //6个字节的硬件地址,即MAC
union{
char ifrn_name[IFNAMESIZ];//网络接口名称
}ifr_ifrn;
union{
struct sockaddr ifru_addr;//本地IP地址
struct sockaddr ifru_dstaddr;//目标IP地址
struct sockaddr ifru_broadaddr;//广播IP地址
struct sockaddr ifru_netmask;//本地子网掩码地址
struct sockaddr ifru_hwaddr;//本地MAC地址
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;//设备协议设置
struct ifmap{//网卡设备的映射属性
unsigned long mem_start;//开始地址
unsigned long mem_end;//结束地址
unsigned short base_addr;//基地址
unsigned char irq;//中断号
unsigned char dma;//DMA
unsigned char port;//端口
}
struct ifconf{//网络配置结构体是一种缓冲区
int ifc_len;//缓冲区ifr_buf的大小
union{
char__user *ifcu_buf;//绘冲区指针
struct ifreq__user* ifcu_req;//指向ifreq指针
}ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf;//缓冲区地址
#define ifc_req ifc_ifcu.ifcu_req;//ifc_req地址
(1)获得配置选项SIOCGIFCONF获得网络接口的配置情况 需要填充struct ifreq中ifr_name变量
(2)其它选项获取填充struct ifreq的ifr_name
**/ int main(int argc,char*argv[]){
int s;
int err;
s=socket(AF_INET,SOCK_DGRAM,);
if(s<){
perror("socket error");
return;
} //传入网络接口序号,获得网络接口的名称
struct ifreq ifr; ifr.ifr_ifindex=;//获得第2个网络接口的名称
err=ioctl(s,SIOCGIFNAME,&ifr); if(err)
perror("index error");
else
printf("the %dst interface is:%s\n",ifr.ifr_ifindex,ifr.ifr_name); //传入网络接口名称,获得标志
memcpy(ifr.ifr_name,"eth0",);
err=ioctl(s,SIOCGIFFLAGS,&ifr);
if(!err)
printf("SIOCGIFFLAGS:%d\n",ifr.ifr_flags); //获得MTU和MAC
err=ioctl(s,SIOCGIFMTU,&ifr);
if(!err)
printf("SIOCGIFMTU:%d\n",ifr.ifr_mtu); //获得MAC地址
err=ioctl(s,SIOCGIFHWADDR,&ifr);
if(!err){
unsigned char* hw=ifr.ifr_hwaddr.sa_data;
printf("SIOCGIFHWADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",hw[],hw[],hw[],hw[],hw[],hw[]);
} //获得网卡映射参数 命令字SIOCGIFMAP
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); //获取网络接口IP struct sockaddr_in *sin=(struct sockaddr_in*)&ifr.ifr_addr;//保存的是二进制IP
char ip[];//字符数组,存放字符串
memset(ip,,);
err=ioctl(s,SIOCGIFADDR,&ifr);
if(!err){
inet_ntop(AF_INET,&sin->sin_addr.s_addr,ip,);//转换的字符串保存到ip数组中,第二个参数是要转换的二进制IP指针,第三个参数是转换完成存放IP的缓冲区,最后一个参数是缓冲区的长度
printf("SIOCGIFADDR:%s\n",ip);
} //查询目标IP地址
err=ioctl(s,SIOCGIFDSTADDR,&ifr);
if(!err){
inet_ntop(AF_INET,&sin->sin_addr.s_addr,ip,);
printf("SIOCGIFDSTADDR:%s\n",ip);
} //查询子网掩码
err=ioctl(s,SIOCGIFNETMASK,&ifr);
if(!err){
inet_ntop(AF_INET,&sin->sin_addr.s_addr,ip,);
printf("SIOCGIFNETMASK:%s\n",ip);
} //设置IP地址,设置网络接口
inet_pton(AF_INET,"222.27.253.108",&sin->sin_addr.s_addr);//将字符串IP转换成二进制
err=ioctl(s,SIOCSIFADDR,&ifr);//发送设置本机ip地址请求命令
if(!err){
printf("check IP-----");
memset(&ifr,,sizeof(ifr));
memcpy(ifr.ifr_name,"eth0",);
ioctl(s,SIOCGIFADDR,&ifr);
inet_ntop(AF_INET,&sin->sin_addr.s_addr,ip,);
printf("%s\n",ip);
} //得到接口的广播地址
memset(&ifr,,sizeof(ifr));
memcpy(ifr.ifr_name,"eth0",);
ioctl(s,SIOCGIFBRDADDR,&ifr);
struct sockaddr_in *broadcast=(struct sockaddr_in*)&ifr.ifr_broadaddr;
//转换成字符串
inet_ntop(AF_INET,&broadcast->sin_addr.s_addr,ip,);//inet_ntop将二进制IP转换成点分十进制的字符串
printf("BROADCAST IP:%s\n",ip);
close(s);
}
查看arp高速缓存信息
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if_arp.h>
#include <string.h>
#include <stdlib.h>
#include <linux/sockios.h>
/**
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];//查询网络接口的名称
}
**/ //根据IP地址查找硬件地址
int main(int argc,char*argv[]){
int s;
int err;
struct arpreq arpreq;
struct sockaddr_in *addr=(struct sockaddr_in*)&arpreq.arp_pa;//IP地址
s=socket(AF_INET,SOCK_DGRAM,);
if(s<)
perror("socket error"); addr->sin_family=AF_INET;
addr->sin_addr.s_addr=inet_addr(argv[]);//转换成二进制IP
if(addr->sin_addr.s_addr==INADDR_NONE)
printf("IP地址格式错误\n"); strcpy(arpreq.arp_dev,"eth0");
err=ioctl(s,SIOCGARP,&arpreq);
if(err==-){
perror("arp");
return -;
} unsigned char* hw=(unsigned char*)&arpreq.arp_ha.sa_data;//硬件地址
printf("%s\n",argv[]);
printf("%02x:%02x:%02x:%02x:%02x:%02x\n",hw[],hw[],hw[],hw[],hw[],hw[]);
close(s);
return ;
}
查看网关的MAC。在查看ARP高速缓存时要传入IP地址与接口信息。而获得接口信息要传入接口名ifr_name,如eth0。
要介绍了获得网络接口请求信息,获得网卡设备映射属性、配置网络接口、获得ARP高速缓存等。其它ioctl函数还能对操作文件,操作I/O、操作路由等。最后对于网络接口的操作与ARP高速缓存的操作分别给出了实例。
ioctl操作的更多相关文章
- Oracle 11gR2 11.2.0.1 ( 11.2.0.1的BUG?):ohasd不能正常启动:ioctl操作:npohasd的问题:【chmod a+wr /var/tmp/.oracle/npohasd】
问题1:执行安装,编译成功后,执行asmca时,失败,无法成功创建后台相关服务 问题2:os系统重启后,ohasd无法正常启动,css服务失败 原因:11.2.0.1的BUG:/var/tmp/.or ...
- UNIX网络编程--ioctl操作(十七)
一.概述 在本书中有两个地方都对这个函数进行了介绍,其实还有很多地方需要这个函数.ioclt函数传统上一直作为纳西而不适合归入其他精细定义类别的特性的系统接口.网络程序(特别是服务器程序)经常在程序启 ...
- linux 高级字符设备驱动 ioctl操作介绍 例程分析实现【转】
转自:http://my.oschina.net/u/274829/blog/285014 1,ioctl介绍 ioctl控制设备读写数据以及关闭等. 用户空间函数原型:int ioctl(int f ...
- UNP学习笔记(第十七章 ioctl操作)
ioctl相当于一个杂物箱,它一直作为那些不适合归入其他精细定义类别的特性的系统接口. 本章笔记先放着,到时候有需要再看 ioctl函数 #include <unistd.h> int i ...
- 《网络编程》ioctl 操作
概要 ioctl 功能与 fcntl 功能类似,它可以被用于描述操作的叙述字符,获取或设置属性的描述是开放式的叙事休息,但在网络编程的两个功能有关的不同类型的操作.fcntl 作.文件操作,而 ioc ...
- UNP学习 ioctl操作
一.ioctl函数 #include <unistd.h> int ioctl(int fd, int request, ... /* void * arg */); 返回:成功0,出错- ...
- (十五)ioctl、ifreq、ifconf
ioctl操作 传统上ioctl函数是用于那些普遍使用,但不适合归入其他类别的任何特性的系统接 口.Posix去掉了ioctl,它通过 创建特殊的其功能已被Posix标准化的包裹函数来代替ioct ...
- ioctl用法详解 (网络)
本函数影响由fd参数引用的一个打开的文件. #include#include int ioctl( int fd, int request, .../* void *arg */ );返回0:成功 ...
- ioctl函数详细说明
本函数影响由fd 参数引用的一个打开的文件. #include<unistd.h> int ioctl( int fd, int request, .../* void *arg */ ) ...
随机推荐
- java直接存取MS Access的mdb数据库文件
jdbc 访问 access 的 mdb 数据库文件,使用一个叫ucanaccess的开发包实现这个功能. "Supported Access formats: 2000,2002/2003 ...
- 机器学习--主成分分析(PCA)算法的原理及优缺点
一.PCA算法的原理 PCA(principle component analysis),即主成分分析法,是一个非监督的机器学习算法,是一种用于探索高维数据结构的技术,主要用于对数据的降维,通过降维可 ...
- python 格式化打印
#coding=utf-8 import time; start_time = time.time()for a in range(0,1001): for b in range(0,1001): f ...
- 说说 Vue.js 中的 v-cloak 指令
可以使用 v-cloak 指令设置样式,这些样式会在 Vue 实例编译结束时,从绑定的 HTML 元素上被移除. 当网络较慢,网页还在加载 Vue.js ,而导致 Vue 来不及渲染,这时页面就会显示 ...
- MySQL基础之STRAIGHT JOIN用法简介
MySQL基础之STRAIGHT JOIN用法简介 引用mysql官方手册的说法: STRAIGHT_JOIN is similar to JOIN, except that the left tab ...
- 纯手打AJAX,还有一个对象转查询字符串的小方法obj=>url
function json2url(json){ var arr=[]; for(var name in json){ arr.push(name+'='+json[name]); } return ...
- C# - 操作Word文档小实验
前言 本篇主要记录:VS2019 WinFrm桌面应用程序实现对Word文档的简单操作. 准备工作 搭建WinFrm前台界面 添加必要的控件,如下图 NuGet包管理器 安装Microsoft.Off ...
- Python读写Excel文件的实例
最近由于经常要用到Excel,需要根据Excel表格中的内容对一些apk进行处理,手动处理很麻烦,于是决定写脚本来处理.首先贴出网上找来的读写Excel的脚本. 1.读取Excel(需要安装xlrd) ...
- python凯撒加密
在密码学中,恺撒密码是一种最简单且最广为人知的加密技术.它是一种替换加密的技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文.例,当偏移量是3的时候,所有的字母A将 ...
- springCloud实战篇——纯文本
什么是微服务架构? 微服务是系统架构的一种设计风格,主旨是将原本独立的系统产分为多个小型的服务,这些服务都在各自的进程中运行.服务与服务之间基于HTTP的RESTful API进行通信协作. 构造背景 ...