ioctl 函数与网络接口.docx
- 文档编号:11403685
- 上传时间:2023-02-28
- 格式:DOCX
- 页数:10
- 大小:17.78KB
ioctl 函数与网络接口.docx
《ioctl 函数与网络接口.docx》由会员分享,可在线阅读,更多相关《ioctl 函数与网络接口.docx(10页珍藏版)》请在冰豆网上搜索。
ioctl函数与网络接口
ioctl函数与网络接口
的应用
#include<unistd.h>
intioctl(intfd,int
request,.../*void*arg*/);
返回0——成功,-1——出错
第一个参数fd指示某个文件描述符(当然也包括套接口描述符)
第二个参数request指示要ioctl执行的操作
第三个参数总是某种指针,具体的指向类型依赖于request参数
我们可以把和网络相关的请求(request)划分为6类:
套接口操作
文件操作
接口操作
ARP高速缓存操作
路由表操作
流系统
下表列出了网络相关ioctl请求的request参数以及arg地址必须指向的数据类型:
类别
request说明(第三个参数)数据类型
SIOCATMARK是否位于带外标记
int
套接口SIOCSPGRP
设置陶接口的进程ID或组IDint
SIOCGPGRP
获取陶接口的进程ID或组IDint
文件FIONBIO
设置/清除非阻塞IO标识int
FIOASYNC
设置/清除信号驱动异步IO标识int
FIONREAD
获取接收缓冲区中的字节数int
……
SIOCGIFCONF
获取所有接口的清单structifconf
接口SIOCSIFADDR
设置接口的ip地址structifreq
SIOCGIFADDR
获取接口地址structifreq
SIOCSIFFLAGS设置接口标识struct
ifreq
SIOCGIFFLAGS
获取接口标识structifreq
SIOCSIFDSTADDR
设置点到点地址structifreq
SIOCGIFDSTADDR获取点到点地址struct
ifreq
SICSIFBRDADDR
设置广播地址structifreq
SICGIFBRDADDR
获取广播地址structifreq
……
SIOCSARP
创建/修改ARP表项structarpreq
ARPSIOCGARP
获取ARP表项structarpreq
SIOCDARP
删除ARP表项structarpreq
路由……
(有很多request请求没有列出,而且不同的系统所提供的request也有所不同,比如linux就不提供SIOCGSIZIFCONF请求)
上面的表中,用ioctl执行接口操作的请求时,要用到结构体structifconf与structifreq
structifconf{
intifc_len;//缓冲区ifcu_buf的大小
union{
caddr_tifcu_buf;//其实就是char*类型。
structifreq*ifcu_req;//
为ifconf分配空间时我们用ifcu_buf指针;当要取得或设置该缓冲区中的ifreq类型时,则用这个指针
}ifc_ifcu;
};
#defineifc_bufifc_ifcu.ifcu_buf//bufferaddress
#defineifc_reqifc_ifcu.ifcu_req//arrayofstructuresreturned
structifreq
{
charifrn_name[IFNAMSIZ];/*ifname,e.g."eth0"
*/
union{
structsockaddrifru_addr;
structsockaddrifru_dstaddr;
structsockaddr
ifru_broadaddr;
structsockaddrifru_netmask;
struct
sockaddrifru_hwaddr;
shortifru_flags;
intifru_ivalue;
intifru_mtu;
structifmapifru_map;
charifru_slave[IFNAMSIZ];/*Justfitsthesize*/
charifru_newname[IFNAMSIZ];
void*ifru_data;
structif_settingsifru_settings;
}ifr_ifru;
};
#defineifr_nameifr_ifrn.ifrn_name/*interface
name*/
#defineifr_hwaddrifr_ifru.ifru_hwaddr/*MAC
address*/
#defineifr_addrifr_ifru.ifru_addr
/*address*/
#defineifr_dstaddrifr_ifru.ifru_dstaddr
/*otherendofp-p
lnk*/
#defineifr_broadaddrifr_ifru.ifru_broadaddr/*broadcast
address*/
#defineifr_netmaskifr_ifru.ifru_netmask/*
interfacenet
mask*/
#defineifr_flagsifr_ifru.ifru_flags/*
flags*/
#defineifr_metricifr_ifru.ifru_ivalue/*
metric*/
#defineifr_mtuifr_ifru.ifru_mtu
/*mtu*/
#defineifr_mapifr_ifru.ifru_map
/*devicemap*/
#define
ifr_slaveifr_ifru.ifru_slave/*slave
device*/
#defineifr_dataifr_ifru.ifru_data/*
forusebyinterface*/
#define
ifr_ifindexifr_ifru.ifru_ivalue/*interface
index*/
#defineifr_bandwidthifr_ifru.ifru_ivalue/*link
bandwidth*/
#define
ifr_qlenifr_ifru.ifru_ivalue/*Queuelength
*/
#defineifr_newnameifr_ifru.ifru_newname/*New
name*/
#defineifr_settingsifr_ifru.ifru_settings/*
Device/protosettings*/
ifconf结构包含了ifreq结构指针,
在使用ifconf之前,我们得先为其ifcu_buf指针(或者说ifcu_req指针)分配缓冲区
其他不知道该怎么说。
贴代码吧。
一个用ioctl实现的类似ifconfig命令的小程序。
#include<stdio.h>//printf()#include<unistd.h>//ioctl()#include<sys/ioctl.h>//ioctl#include<sys/socket.h>//socket()#include<net/if.h>//structifconf{}&structifreq{}#include<string.h>//strcpy()#include<arpa/inet.h>//inet_ntoa()#include<stdlib.h>//malloc()&free()
intprint_if_addr(intfd,char*interface_name);//打印接口的ip地址intprint_if_mac(intfd,char*interface_name);//打印接口的mac地址intprint_if_broadaddr(intfd,char*interface_name);//打印接口的广播地址intprint_if_mask(intfd,char*interface_name);//打印接口的掩码intprint_if_mtu(intfd,char*interface_name);//打印接口的mtuintprint_all_interface();//打印所有接口的基本信息intprint_if_addr6(char*interface_name);//打印接口的ipv6地址intprint_interface_info(char*interface_name);//打印接口的以上所有信息intset_if_up(char*interface_name);//启动接口intset_if_down(char*interface_name);//关闭接口intset_if_ip(char*interface_name,char*ip_str);//设置接口的ip地址voidusage();//打印该程序的使用手册
intmain(intargc,char**argv){intsockfd;
printf("\n**********funway:
用ioctl函数来实现ifconfig命令的效果**********\n");
switch(argc){case1:
print_all_interface();break;case2:
print_interface_info(argv[1]);break;case3:
if(strcmp(argv[2],"up")==0)set_if_up(argv[1]);elseif(strcmp(argv[2],"down")==0)set_if_down(argv[1]);elseset_if_ip(argv[1],argv[2]);break;default:
usage();break;}
return0;}
voidusage(){printf("usage:
./myifconfig[interface[down|up|ip]]\n");}
intprint_if_addr(intfd,char*if_name){structsockaddr_in*ip;structifreqifr;
strcpy(ifr.ifr_name,if_name);
if(ioctl(fd,SIOCGIFADDR,&ifr)<0){perror("ioctlSIOCGIFADDRerror");return-1;}ip=(structsockaddr_in*)&ifr.ifr_addr;//获得ipv4地址printf("IP:
%s\n",inet_ntoa(ip->sin_addr));//将ipv4地址转换为主机字节序的字符串并输出return0;}
intprint_if_broadaddr(intfd,char*if_name){structsockaddr_in*ip;structifreqifr;
strcpy(ifr.ifr_name,if_name);
if(ioctl(fd,SIOCGIFBRDADDR,&ifr)<0){perror("ioctlSIOCGIFBRDADDRerror");return-1;}ip=(structsockaddr_in*)&ifr.ifr_broadaddr;//获得广播地址printf("Broadcast:
%s\n",inet_ntoa(ip->sin_addr));return0;}
intprint_if_mask(intfd,char*if_name){structsockaddr_in*ip;structifreqifr;
strcpy(ifr.ifr_name,if_name);
if(ioctl(fd,SIOCGIFNETMASK,&ifr)<0){perror("ioctlSIOCGIFNETMASKerror");return-1;}ip=(structsockaddr_in*)&ifr.ifr_ifru.ifru_netmask;//获得子网掩码。
注意!
我们仍放在structaockaddr_in结构中返回printf("Mask:
%s\n",inet_ntoa(ip->sin_addr));return0;}
intprint_if_mac(intfd,char*if_name){unsignedchar*p;//注意!
这里要用unsignedchar,而不是char!
因为char要对[1xxxxxxx]这样的数进行补码运算的。
//但我们等下要打印的mac地址是不需要符号的数值structifreqifr;
strcpy(ifr.ifr_name,if_name);
if(ioctl(fd,SIOCGIFHWADDR,&ifr)<0){perror("ioctlSIOCGIFHWADDRerror");return-1;}p=(char*)&ifr.ifr_ifru.ifru_hwaddr.sa_data[0];//获得接口的MAC地址,用字符串指针返回printf("MAC:
%02x:
%02x:
%02x:
%02x:
%02x:
%02x\n",*p,*(p+1),*(p+2),*(p+3),*(p+4),*(p+5));//printf("MAC:
%02x:
%02x:
%02x:
%02x:
%02x:
%02x\n",*p++,*p++,*p++,*p++,*p++,*p++);//这么写会导致输出为倒序。
这并不是p指针有什么问题,不信你可以用//for(;;)//printf(p++);//来试验就是正确的,我猜倒序的原因是编译器的优化问题吧return0;}
intprint_if_mtu(intfd,char*if_name){unsignedintmtu;structifreqifr;
strcpy(ifr.ifr_name,if_name);
if(ioctl(fd,SIOCGIFMTU,&ifr)<0){perror("ioctlSIOCGIFMTUerror");return-1;}mtu=ifr.ifr_ifru.ifru_mtu;//获得子网掩码。
注意!
我们仍放在structaockaddr_in结构中返回printf("MTU:
%d\n",mtu);return0;}
intprint_if_addr6(char*if_name){unsignedintmtu;structifreqifr;intsockfd;if((sockfd=socket(AF_INET6,SOCK_DGRAM,0))<0){perror("Socketerror");return-1;}//创建用来检查网络接口的套接字
/*strcpy(ifr.ifr_name,if_name);
if(ioctl(fd,SIOCGIFMTU,&ifr)<0){perror("ioctlSIOCGIFMTUerror");return-1;}mtu=ifr.ifr_ifru.ifru_mtu;//获得子网掩码。
注意!
我们仍放在structaockaddr_in结构中返回printf("ipv6:
%d\n",mtu);*///未写完,不知道怎么获得ipv6地址。
。
。
return0;}
intprint_all_interface(){structifconfifc;structifreq*ifr_p;intsockfd,len,old_len=0,i;char*buf;
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0){perror("Socketerror");return-1;}//创建用来检查网络接口的套接字len=10*sizeof(structifreq);for(;;){if((buf=malloc(len))==NULL){perror("mallocerror");return-1;}ifc.ifc_len=len;ifc.ifc_buf=buf;if(ioctl(sockfd,SIOCGIFCONF,&ifc)<0){perror("ioctlSIOCGIFCONFerror");return-1;}if(ifc.ifc_len==old_len)break;old_len=ifc.ifc_len;len+=10*sizeof(structifreq);free(buf);}printf("wehave%dinterfaces\n",ifc.ifc_len/sizeof(structifreq));for(i=0;i<ifc.ifc_len/sizeof(structifreq);i++){ifr_p=&ifc.ifc_req[i];printf("\ninterface[%s]:
\n",ifr_p->ifr_name);
print_if_addr(sockfd,ifr_p->ifr_name);print_if_broadaddr(sockfd,ifr_p->ifr_name);print_if_mask(sockfd,ifr_p->ifr_name);print_if_mac(sockfd,ifr_p->ifr_name);print_if_mtu(sockfd,ifr_p->ifr_name);}close(sockfd);return0;}
intprint_interface_info(char*if_name){intsockfd;if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0){perror("Socketerror");return-1;}//创建用来检查网络接口的套接字
printf("%s:
\n",if_name);print_if_addr(sockfd,if_name);print_if_broadaddr(sockfd,if_name);print_if_mask(sockfd,if_name);print_if_mac(sockfd,if_name);print_if_mtu(sockfd,if_name);close(sockfd);return0;}
intset_if_up(char*if_name)//启动接口{structifreqifr;intsockfd;
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0){perror("Socketerror");return-1;}//创建用来检查网络接口的套接字
strcpy(ifr.ifr_name,if_name);if(ioctl(sockfd,SIOCGIFFLAGS,&ifr)<0){perror("ioctlSIOCGIFFLAGSerror");return-1;}ifr.ifr_flags|=IFF_UP;if(ioctl(sockfd,SIOCSIFFLAGS,&ifr)<0){perror("ioctlSIOCSIFFLAGSerror");return-1;}return0;}
intset_if_down(char*if_name)//关闭接口{structifreqifr;intsockfd;
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0){perror("Socketerror");return-1;}//创建用来检查网络接口的套接字
strcpy(ifr.ifr_name,if_name);if(ioctl(sockfd,SIOCGIFFLAGS,&ifr)<0){perror("ioctlSIOCGIFFLAGSerror");return-1;}ifr.ifr_flags&=~IFF_UP;//将IIF_UP取反后与原来的标志进行与运算。
if(ioctl(sockfd,SIOCSIFFLAGS,&ifr)<0){perror("ioctlSIOCSIFFLAGSerror");return-1;}return0;}
intset_if_ip(char*if_name,char*ip_str)//设置接口的ip地址{structifreqifr;structsockaddr_inip_addr;intsockfd;
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0){perror("Socketerror");return-1;}//创建用来检查网络接口的套接字ip_addr.sin_family=AF_INET;if(inet_pton(AF_INET,ip_str,&ip_addr.sin_addr)<1){perror("erroripv4addr:
");return-1;}strcpy(ifr.ifr_name,if_name);memcpy(&ifr.ifr_addr,&ip_addr,sizeof(structsockaddr_in));if(ioctl(soc
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ioctl 函数与网络接口 函数 网络 接口