c++之ioctl

#include <unistd.h>
int ioctl(int fd, int request, /* void *arg */)
返回值:成功0,失败-1

我们可以把和网络相关的请求划分为6类:

  1. 套接口操作
  2. 文件操作
  3. 接口操作
  4. ARP高速缓存操作
  5. 路由表操作
  6. 流系统
类别Request说明数据类型
套接字SIOCATMARK是否位于带外标记int
SIOCSPGRP设置套接口的进程ID或进程组IDint
SIOCGPGRP获取套接口的进程ID或进程组IDint
文件FIONBIN设置/清除非阻塞I/O标志int
FIOASYNC设置/清除信号驱动异步I/O标志int
FIONREAD获取接收缓存区中的字节数int
FIOSETOWN设置文件的进程ID或进程组IDint
FIOGETOWN获取文件的进程ID或进程组IDint
接口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获取接口MTUstruct ifreq
SIOCxxx(还有很多取决于系统的实现)struct ifreq
ARPSIOCSARP创建/修改ARP表项struct arpreq
SIOCGARP获取ARP表项struct arpreq
SIOCDARP删除ARP表项struct arpreq
路由SIOCADDRT增加路径struct rtentry
SIOCDELRT删除路径struct rtentry
I_xxx

套接字操作

明确用于套接口操作的ioctl请求有三个,它们都要求ioctl的第三个参数是指向某个整数的一个指针。

--
SIOCATMARK:POSIX以函数sockatmark替换本请求。
SIOCGPGRP:通过第三个参数指向的整数返回本套接口的进程ID或进程组ID,该ID指定针对本套接口的SIGIO或SIGURG信号的接收进程。本请求和fcntl的F_GETOWN命令等效,POSIX标准化的是fcntl函数。
SIOCSPGRP:把本套接口的进程ID或者进程组ID设置成第三个参数指向的整数,该ID指定针对本套接口的SIGIO或SIGURG信号的接收进程,本请求和fcntl的F_SETOWN命令等效,POSIX标准化的是fcntl操作

文件操作

--
FIONBIO:根据ioctl的第三个参数指向一个0或非0值分别清除或设置本套接口的非阻塞标志。本请求和O_NONBLOCK文件状态标志等效,而该标志通过fcntl的F_SETFL命令清除或设置。
FIOASYNC:根据iocl的第三个参数指向一个0值或非0值分别清除或设置针对本套接口的信号驱动异步I/O标志,它决定是否收取针对本套接口的异步I/O信号(SIGIO)。本请求和O_ASYNC文件状态标志等效,而该标志可以通过fcntl的F_SETFL命令清除或设置。
FIONREAD:通过由ioctl的第三个参数指向的整数返回当前在本套接口接收缓冲区中的字节数。本特性同样适用于文件,管道和终端。
FIOSETOWN:对于套接口和SIOCSPGRP等效
FIOGETOWN:对于套接口和SIOCGPGRP等效

接口配置:
得到系统中所有接口由SIOCGIFCONF请求完成,该请求使用ifconf结构,ifconf又使用ifreq结构,如下所示:

Struct ifconf{
    int ifc_len;                 // 缓冲区的大小
    union{
        caddr_t ifcu_buf;        // input from user->kernel
        struct ifreq *ifcu_req;    // return of structures returned
    }ifc_ifcu;
};
#define  ifc_buf  ifc_ifcu.ifcu_buf    //buffer address

#define  ifc_req  ifc_ifcu.ifcu_req    //array of structures returned

#define  IFNAMSIZ  16

struct ifreq{
    char ifr_name[IFNAMSIZ];           // interface name, e.g., “le0”
    union{
        struct sockaddr ifru_addr;
        struct sockaddr ifru_dstaddr;
        struct sockaddr ifru_broadaddr;
        short ifru_flags;
        int ifru_metric;
        caddr_t ifru_data;
    }ifr_ifru;
};

#define ifr_addr     ifr_ifru.ifru_addr            // address

#define ifr_dstaddr   ifr_ifru.ifru_dstaddr         // otner end of p-to-p link

#define ifr_broadaddr ifr_ifru.ifru_broadaddr    // broadcast address

#define ifr_flags     ifr_ifru.ifru_flags        // flags

#define ifr_metric    ifr_ifru.ifru_metric      // metric

#define ifr_data      ifr_ifru.ifru_data        // for use by interface

再调用ioctl前我们必须先分撇一个缓冲区和一个ifconf结构,然后才初始化后者。如下图
展示了一个ifconf结构的初始化结构,其中缓冲区ifc_buf的大小ifc_len为1024,ioctl的第三个参数指向这样一个ifconf结构。假设内核返回2个ifreq结构,ioctl返回时通过同一个ifconf结构缓冲区填入了那2个ifreq结构,ifconf结构的ifc_len成员也被更新,以反映存放在缓冲区中的信息量

接口操作

SIOCGIFCONF请求为每个已配置的接口返回其名字以及一个套接口地址结构。我们接着可以发出多个接口类其他请求以设置或获取每个接口的其他特征。这些请求的获取(get)版本(SIOCGxxx)通常由netstat程序发出,设置(set)版本(SIGOCSxxx)通常由ifconfig程序发出。任何用户都可以获取接口信息,设置接口信息却要求有超级用户权限。

这些请求汲取或返回一个一个ifreq结构中的信息,而这个结构的地址则作为ioctl调用的第三个参数制定。接口总是以其名标志,在ifreq结构的ifr_name成员中指定,如le0,lo0,ppp0等。

这些请求中有许多使用套接口地址结构在应用进程和内核之间指定或返回具体接口的IP地址或地址掩码。对于IPV4,这个地址或掩码放在一个网际套接口地址结构的sin_addr成员中;对于IPV6,它是一个IPV6套接口地址结构的sin6_addr成员。

--
SIOCGIFADDR:在ifr_addr成员中返回单播地址。
SIOCSIFADDR:用ifr_addr成员设置接口地址,这个接口的初始化函数也被调用。
SIOCGIFFLAGS:在ifr_flags成员中返回接口标志。这些接口标志的名字格式为IFF_XXX,在<net/if.h>头文件中定义。举例来说,这些标志指示接口是否处于UP即在工状态(IFF_UP),是否为一个点到点接口(IFF_POINTOPOINT),是否支持广播(IFF_BROADCAST),等等。
SIOCSIFFLAGS:用ifr_flags成员设置接口标志。
SIOCGIFDSTADDR:在ifr_dstaddr成员中返回点到点地址。
SIOCSIFDSTADDR:在ifr_dstaddr成员中设置点到点地址
SIOCGIFBRDADDR:在ifr_broadaddr成员中返回广播地址。应用进程必须首先获取接口标志,然后发出正确的请求;对于广播接口为SIOCGIFBRDADDR,对于点到点接口为SIOCGIFDSTADDR
SIOCSIFBRDADDR:用ifr_broadaddr成员设置广播地址。
SIOCGIFNETMASK:在ifr_addr成员中返回子网掩码。
SIOCSIFNETMASK:在ifr_addr成员中设置子网掩码。
SIOCGIFMETRIC:用ifr_metric成员返回接口测度。接口测度由内核为每个接口维护,不过使用他的是路由守护进程routed。接口测度被routed加到跳数上。
SIOCSIFMETRIC:用ifr_metric成员设置接口的路由测度。

例子

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
void err_sys(const char *errmsg);
int main(void)
{               
	int i, sockfd;
	struct ifreq ifr;
	struct arpreq arpr;
	strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));
	if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
		err_sys("socket");       
	/* get ip address */
	if (ioctl(sockfd, SIOCGIFADDR, &ifr) == -1)       
		err_sys("1-ioctl");
	/* get hardware address */
	ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
	if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) == -1)
		err_sys("2-ioctl");
	/* output hardware address */
	for (i = 0; i < 6; i++) {
		unsigned char *mac = (unsigned char *) ifr.ifr_hwaddr.sa_data;
		printf("%x", (int) mac[i]);
		if (i != 5)
			printf("%c", ':');
	}
	exit(0);
}
void err_sys(const char *errmsg)
{
	perror(errmsg);
	exit(1);
}

转载自:https://www.cnblogs.com/kunhu/p/3606427.html

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值