UNIX网络编程——ioctl 函数的用法详解

1.介绍

       Linux网络程序与内核交互的方法是通过ioctl来实现的,ioctl与网络协议栈进行交互,可得到网络接口的信息,网卡设备的映射属性和配置网络接口。并且还能够查看,修改,删除ARP高速缓存的信息,所以,我们有必要了解一下ioctl函数的具体实现。


2.相关结构体与相关函数

#include <sys/ioctl.h>int ioctl(int d,int request,....);
参数:

d-文件描述符,这里是对网络套接字操作,显然是套接字描述符。

request-请求码

省略的部分对应不同的内存缓冲区,而具体的内存缓冲区是由请求码request来决定的,下面看一下具体都有哪些相关缓冲区。

(1)网络接口请求结构ifreq

struct ifreq
{#define IFHWADDRLEN 6 //6个字节的硬件地址,即MACunion{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;//设备协议设置
       如果想获得网络接口的相关信息,就传入ifreq结构体。


(2)网卡设备属性ifmap

struct ifmap{//网卡设备的映射属性unsigned long mem_start;//开始地址unsigned long mem_end;//结束地址unsigned short base_addr;//基地址unsigned char irq;//中断号unsigned char dma;//DMAunsigned char port;//端口
}

(3)网络配置接口ifconf

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地址

(4)ARP高速缓存操作arpreq

/* 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];//查询网络接口的名称
}


3. 请求码request

类别

Request

说明

数据类型

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. 相关例子

(1)网络接口信息
       选项获取填充struct ifreq的ifr_name:

#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;//DMAunsigned 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,0);if(s<0){perror("socket error");return;}//传入网络接口序号,获得网络接口的名称struct ifreq ifr;ifr.ifr_ifindex=2;//获得第2个网络接口的名称err=ioctl(s,SIOCGIFNAME,&ifr);if(err)perror("index error");elseprintf("the %dst interface is:%s\n",ifr.ifr_ifindex,ifr.ifr_name);//传入网络接口名称,获得标志memcpy(ifr.ifr_name,"eth0",5);err=ioctl(s,SIOCGIFFLAGS,&ifr);if(!err)printf("SIOCGIFFLAGS:%d\n",ifr.ifr_flags);//获得MTU和MACerr=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[0],hw[1],hw[2],hw[3],hw[4],hw[5]);}//获得网卡映射参数 命令字SIOCGIFMAPerr=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);//获取网络接口IPstruct sockaddr_in *sin=(struct sockaddr_in*)&ifr.ifr_addr;//保存的是二进制IPchar ip[16];//字符数组,存放字符串memset(ip,0,16);err=ioctl(s,SIOCGIFADDR,&ifr);if(!err){inet_ntop(AF_INET,&sin->sin_addr.s_addr,ip,16);//转换的字符串保存到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,16);printf("SIOCGIFDSTADDR:%s\n",ip);}//查询子网掩码err=ioctl(s,SIOCGIFNETMASK,&ifr);if(!err){inet_ntop(AF_INET,&sin->sin_addr.s_addr,ip,16);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,0,sizeof(ifr));memcpy(ifr.ifr_name,"eth0",5);ioctl(s,SIOCGIFADDR,&ifr);inet_ntop(AF_INET,&sin->sin_addr.s_addr,ip,16);printf("%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);//inet_ntop将二进制IP转换成点分十进制的字符串printf("BROADCAST IP:%s\n",ip);close(s);
}
运行结果:


(2)查看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,0);if(s<0)perror("socket error");addr->sin_family=AF_INET;addr->sin_addr.s_addr=inet_addr(argv[1]);//转换成二进制IPif(addr->sin_addr.s_addr==INADDR_NONE)printf("IP地址格式错误\n");strcpy(arpreq.arp_dev,"eth0");err=ioctl(s,SIOCGARP,&arpreq);if(err==-1){perror("arp");return -1;}unsigned char* hw=(unsigned char*)&arpreq.arp_ha.sa_data;//硬件地址printf("%s\n",argv[1]);printf("%02x:%02x:%02x:%02x:%02x:%02x\n",hw[0],hw[1],hw[2],hw[3],hw[4],hw[5]);close(s);return 0;
}
运行结果:

                                                         


       查看网关的MAC。在查看ARP高速缓存时要传入IP地址与接口信息。而获得接口信息要传入接口名ifr_name,如eth0。

总结:

       本文主要介绍了获得网络接口请求信息,获得网卡设备映射属性、配置网络接口、获得ARP高速缓存等。其它ioctl函数还能对操作文件,操作I/O、操作路由等。最后对于网络接口的操作与ARP高速缓存的操作分别给出了实例。


转载于:https://www.cnblogs.com/hehehaha/p/6332441.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/301054.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

你对求生欲,一无所知!| 今日最佳

全世界只有3.14 % 的人关注了青少年数学之旅【1】【2】【3】【4】【5】【6】【7】【8】【9】【10】【11】【12】【13】【14】【15】&#xff08;图源网络&#xff0c;侵权删&#xff09;学到了吗&#xff1f;↓ ↓ ↓

C#位图BitArray 小试牛刀

前面聊了布隆过滤器&#xff0c;回归认识一下位图BitMap&#xff0c;阅读前文的同学应该发现了布隆过滤器本身就是基于位图&#xff0c;是位图的一种改进。难缠的布隆过滤器&#xff0c;这次终于通透了位图先看一个问题&#xff0c; 假如有1千万个整数&#xff0c;整数范围在1到…

装上了Visual Studio 2005

为了下Visual Studio 2005&#xff0c;我装上了从来没用过的BT&#xff0c;开着电脑下了一夜&#xff0c;今天早上终于下完了&#xff0c;2.6G呀&#xff0c;多么浩大的工程&#xff0c;比PES5还大。现在的软件动不动就是DVD&#xff0c;要不是还有个刻录机&#xff0c;我的硬盘…

在asp.net core 下定义统一的入参和出参格式

在使用.net core 开发Api的过程中&#xff0c;为了统一输入参数的格式&#xff0c;并增加一些全局必须含有的字段&#xff0c;比如&#xff1a;Code&#xff0c;Message&#xff0c;Lang等等&#xff0c;能采取的变通方式还是有几种的&#xff0c;然而都不够优雅&#xff0c;为…

泰勒定理的奇闻轶事

全世界只有3.14 %的人关注了青少年数学之旅泰勒展式 (Taylor expansion) 的剩余项救人一命&#xff01;在俄国革命期间&#xff08;1917年左右&#xff09;&#xff0c;数学物理学家塔姆 (Igor Tamm) 外出找食物&#xff0c;在靠近敖德萨 (Odessa) 的乡间被反共产主义的保安人员…

6月统计|.NET薪资一旦高起来,岂是其他语言能比的!

全国程序员6月平均薪资出来了&#xff0c;帝都和魔都平均工资超过18k&#xff0c;你被平均了吗&#xff1f;而中位数17k&#xff0c;你拖后腿了吗&#xff1f;当然&#xff0c;.NET开发者的目标不是平均工资&#xff0c;而是double&#xff01;年初跳槽季&#xff0c;腾讯、阿里…

剑桥大学的下午茶,为何能喝出六十位诺贝尔奖获得者?

全世界只有3.14 %的人关注了青少年数学之旅英国人的骄傲是他们有世界上最古老的大学&#xff0c;创立于1209年的剑桥大学。英国剑桥大学每天下午有两个小时的时间&#xff0c;常常有计划、有组织地安排不同学科的权威教授一起在学校咖啡屋或茶园共进下午茶。在这里&#xff0c;…

使用bat来运行cygwin,执行脚本(命令)

2019独角兽企业重金招聘Python工程师标准>>> 这是一个没有意义的问题。 既然要跑脚本。为啥不直接在linux服务器上运行。 这个不是个人能决定的。 一般我都将功能写成jar&#xff0c;或者py, 然后编写bat文件&#xff0c; 如果是java的话&#xff0c;“java -jar…

.NET 下载、文档访问新姿势

dot.net 新的重定向Intro不知道大家之前有没有注意过&#xff0c;如果你访问 https://dot.net 的时候会自动地重定向到 https://dotnet.microsoft.com&#xff0c;想要访问 https://dot.net/download 的时候还是会重定向到 https://dotnet.microsoft.com&#xff0c;不会带着…

excel保存成matlab,matlab数据保存为excel文件

读取&#xff1a;A xlsread(‘Excel路径Excel的名称‘&#xff0c;‘工作表名称‘)例子&#xff1a;A xlsread(‘创新班.xlsx‘,‘Sheet2‘)A xlsread(‘创新班.xlsx‘,‘Sheet2‘,‘a1:c1‘) %读取a1 b1 c1的数据不写工作表名称&#xff0c;默认是第一个。写入&#xff1a;…

客户想你死系列,哈哈哈设计师不容易啊! | 今日最佳

全世界只有3.14 % 的人关注了青少年数学之旅&#xff08;图源网络&#xff0c;侵权删&#xff09;学到了吗&#xff1f;↓ ↓ ↓

DropDownList 選項改變確認腳本

需要這個, 到網找了某先生的腳本改了改 staticpublicstringDropDownListSelectChangeConfirmScript(stringdropDownListId,stringmessage){ string script " <script> \n" " var fooIndex; \n" " function saveIndexes() \n&…

王炸!Azure云助力.NET6现高光时刻(VS2022实战尝鲜)

Azure 是一个云平台&#xff0c;旨在简化构建新式应用程序的过程。无论是选择完全在 Azure 中托管应用程序&#xff0c;还是使用 Azure 服务扩展本地应用程序&#xff0c;Azure 都可以帮助你创建可缩放且可维护的可靠应用程序。凭借你已在使用的工具&#xff08;如 Visual Stud…

求生之路:博士生涯的17条简单生存法则

全世界只有3.14 % 的人关注了青少年数学之旅Next Scientist 是一个专门帮助博士生获取并保持动力、实现毕业和指导在业界求职的网站。本文作者 Julio Peironcely 就是 Next Scientist 的创始人和编辑&#xff0c;曾在荷兰莱顿大学的 PhD 期间做代谢组学和代谢产物鉴定的研究。在…

如何让自己更自律

之前写过一篇如何克服拖延的文章《想得很好&#xff0c;做起来总是不行&#xff1f;》&#xff0c;这次聊得更主动一些&#xff0c;「如何让自己变得自律」&#xff0c;更积极主动地拥抱未来的自己。Sam Thomas Davies曾经精辟地概括过「自律」。他认为自律就是学会抵抗。不管你…

Linux集群服务知识点总结及通过案例介绍如何实现高性能web服务(三)

三&#xff1a;通过corosyncpacemaker实现web服务高可用&#xff0c;主要实现步骤&#xff1a;既然给web应用服务器做高可用&#xff0c;那么httpd进程就不能开机自动运行&#xff0c;而且当前httpd服务属于停止状态&#xff0c;有corosync来自动启动某台的httpd进程12[rootRea…

java hashmap实例,关于java中的HashMap的实例操作

HashMap简介&#xff1a;1、以(键&#xff0c;值)对存储数据。2、不允许有重复的键&#xff0c;但允许有重复的值。3、不同步(多个线程可以同时访问)相关视频教程推荐&#xff1a;java在线学习实例演示如下&#xff1a;1、添加HashMap hash_map new HashMap();hash_map.put( &…

WPF实现仪表盘(刻度跟随)

WPF开发者QQ群&#xff1a; 340500857 | 微信群 -> 进入公众号主页 加入组织“ 前言&#xff0c;接着上一篇圆形进度条。”欢迎转发、分享、点赞、在看&#xff0c;谢谢~。 01—效果预览效果预览&#xff08;更多效果请下载源码体验&#xff09;&#xff1a;02—代码如下一…

数学特级教师:数学除了做习题,我还他让他们看这十部纪录片!

全世界只有3.14 % 的人关注了青少年数学之旅今天我们要向大家强烈推荐一个分享数学知识、严选数学好物公众号“数学好物”。“数学好物”是一个致力为数学爱好者与家长&#xff0c;提供丰富的数学文化、数理思维知识、最新数学好物的公众号。就是他啦&#xff1a;长按二维码可以…

自适应布局

浮动 一列绝对定位,一列用margin撑开空间 margin负值:主体用一层包裹,浮动,内层用margin留出空间;其他列浮动,使用margin调整到空出的位置 1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"2 "http://www.w3.org/TR/html4/strict.dtd">3 …