ioctl 函数

本函数影响由fd 参数引用的一个打开的文件。

#include<unistd.h>

int ioctl( int fd, int request, .../* void *arg */ );

返回0 :成功    -1 :出错

第三个参数总是一个指针,但指针的类型依赖于request 参数。

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

套接口操作

文件操作

接口操作

ARP 高速缓存操作

路由表操作

流系统

下表列出了网络相关ioctl 请求的request 参数以及arg 地址必须指向的数据类型:

类别

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

套接口操作:

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

SIOCATMARK:    如果本套接口的的度指针当前位于带外标记,那就通过由第三个参数指向的整数返回一个非0 值;否则返回一个0 值。POSIX 以函数sockatmark 替换本请求。

SIOCGPGRP :       通过第三个参数指向的整数返回本套接口的进程ID 或进程组ID ,该ID 指定针对本套接口的SIGIO 或SIGURG 信号的接收进程。本请求和fcntl 的F_GETOWN 命令等效,POSIX 标准化的是fcntl 函数。

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

文件操作:

以下5 个请求都要求ioctl 的第三个参数指向一个整数。

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 结构的初始化结构,其中缓冲区的大小为1024 ,ioctl 的第三个参数指向

这样一个ifconf 结构。

ifc_len

Ifc_buf

1024

---------------------> 缓存

假设内核返回2 个ifreq 结构,ioctl 返回时通过同一个ifconf 结构缓冲区填入了那2 个ifreq 结构,ifconf 结构的ifc_len 成员也被更新,以反映存放在缓冲区中的信息量

一般来讲ioctl在用户程序中的调用是:
ioctl(int fd,int command, (char*)argstruct)
ioctl调用与网络编程有关(本文只讨论这一点),文件描述符fd实际上是由socket()系统调用返回的。参数command的取值由/usr/include/linux/sockios.h 所规定。这些command的由于功能的不同,可分为以下几个小类:
• 改变路由表 (例如 SIOCADDRT, SIOCDELRT), 
• 读/更新 ARP/RARP 缓存(如:SIOCDARP, SIOCSRARP), 
• 一般的与网络接口有关的(例如 SIOCGIFNAME, SIOCSIFADDR 等等) 
在 Gooodies目录下有很多样例程序展示了如何使用ioctl。当你看这些程序时,注意参数argstruct是与参数command相关的。例如,与 路由表相关的ioctl使用rtentry这种结构,rtentry定义在/usr/include/linux/route.h(参见例子 adddefault.c)。与ARP有关的ioctl调用使用arpreq结构,arpreq定义在/usr/include/linux /if_arp.h(参见例子arpread.c)
与网络接口有关的ioctl调用使用的command参数通常看起来像SIOCxIFyyyy的形式,这里x要 么是S(设定set,写write),要么是G(得到get,读read)。在getifinfo.c程序中就使用了这种形式的command参数来读 IP地址,硬件地址,广播地址和得到与网络接口有关的一些标志(flag)。在这些ioctl调用中,第三个参数是ifreq结构,它在/usr /include/linux/if.h中定义。在某些情况下, ioctrl调用可能会使用到在sockios.h之外的新的定义。
 

实例:

程序1:检测接口的 .net_addr,netmask,broad_addr
程序2:检查接口的物理连接是否正常
程序3:更简单一点测试物理连接
程序4:调节音量

***************************程序1****************************************
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>

#include <sys/types.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <sys/ioctl.h>
#include <net/if.h>

static void usage(){
        printf("usage : ipconfig interface \n");
        exit(0);
}

int main(int argc,char **argv)
{
        struct sockaddr_in *addr;
        struct ifreq ifr;
        char *name,*address;
        int sockfd;

if(argc != 2)
                usage();
        else
                name = argv[1]; 内容来自ltesting.net

sockfd = socket(AF_INET,SOCK_DGRAM,0);
        strncpy(ifr.ifr_name,name,IFNAMSIZ-1);

if(ioctl(sockfd,SIOCGIFADDR,&ifr) == -1)
                perror("ioctl error"),exit(1);
        addr = (struct sockaddr_in *)&(ifr.ifr_addr);
        address = inet_ntoa(addr->sin_addr);
        printf("inet addr: %s ",address);

if(ioctl(sockfd,SIOCGIFBRDADDR,&ifr) == -1)
                perror("ioctl error"),exit(1);
        addr = (struct sockaddr_in *)&ifr.ifr_broadaddr; 
        address = inet_ntoa(addr->sin_addr);
        printf("broad addr: %s ",address);

if(ioctl(sockfd,SIOCGIFNETMASK,&ifr) == -1)
                perror("ioctl error"),exit(1);
        addr = (struct sockaddr_in *)&ifr.ifr_addr;
        address = inet_ntoa(addr->sin_addr);
        printf("inet mask: %s ",address);

printf("\n");
        exit(0);
}

******************************** 程序2*****************************************************
#include <stdio.h>
#include <string.h>
#include <errno.h> 
#include <fcntl.h>
#include <getopt.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdlib.h>
#include <unistd.h>

typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned char u8;

#include <linux/ethtool.h>
#include <linux/sockios.h>

int detect_mii(int skfd, char *ifname)
{
        struct ifreq ifr;
        u16 *data, mii_val;
        unsigned phy_id;

/* Get the vitals from the interface. */
        strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
        if (ioctl(skfd, SIOCGMIIPHY, &ifr) < 0) 
        {
                fprintf(stderr, "SIOCGMIIPHY on %s failed: %s\n", ifname,
                strerror(errno));
                (void) close(skfd);
                return 2;
        }

data = (u16 *)(&ifr.ifr_data);
        phy_id = data[0];
        data[1] = 1;

if (ioctl(skfd, SIOCGMIIREG, &ifr) < 0)
        {
                fprintf(stderr, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name, 领测软件测试网http://www.ltesting.net 
                strerror(errno));
                return 2;
        }

mii_val = data[3];

return(((mii_val & 0x0016) == 0x0004) ? 0 : 1);
}

int detect_ethtool(int skfd, char *ifname)
{
        struct ifreq ifr;
        struct ethtool_value edata;

memset(&ifr, 0, sizeof(ifr));
        edata.cmd = ETHTOOL_GLINK;

strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)-1);
        ifr.ifr_data = (char *) &edata;

if (ioctl(skfd, SIOCETHTOOL, &ifr) == -1) 
        {
                printf("ETHTOOL_GLINK failed: %s\n", strerror(errno));
                return 2;
        }

return (edata.data ? 0 : 1);
}

int main(int argc, char **argv)
{
        int skfd = -1;
        char *ifname;
        int retval;

if( argv[1] )
                ifname = argv[1];
        else
                ifname = "eth0";

/* Open a socket. */
        if (( skfd = socket( AF_INET, SOCK_DGRAM, 0 ) ) < 0 )
        {
                printf("socket error\n");
                exit(-1);
        }

retval = detect_ethtool(skfd, ifname);

if (retval == 2)
                retval = detect_mii(skfd, ifname);

close(skfd);

if (retval == 2)
                printf("Could not determine status\n");

if (retval == 1)
                printf("Link down\n");

if (retval == 0)
                printf("Link up\n");

return retval;
}

*******************************程序3*****************************************************
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <sys/ioctl.h>
#define LINKTEST_GLINK 0x0000000a

struct linktest_value {
        unsigned int    cmd;
        unsigned int    data; 
};

static
void
usage(const char * pname)
{
        fprintf(stderr, "usage: %s <device>\n", pname);
        fprintf(stderr, "returns: \n");
        fprintf(stderr, "\t 0: link detected\n");
        fprintf(stderr, "\t%d: %s\n", ENODEV, strerror(ENODEV));
        fprintf(stderr, "\t%d: %s\n", ENONET, strerror(ENONET));
        fprintf(stderr, "\t%d: %s\n", EOPNOTSUPP, strerror(EOPNOTSUPP));
        exit(EXIT_FAILURE);
}

static
int
linktest(const char * devname)
{
        struct ifreq ifr;
        struct linktest_value edata;
        int fd;

/* setup our control structures. */
        memset(&ifr, 0, sizeof(ifr));
        strcpy(ifr.ifr_name, devname);

/* open control socket. */
        fd=socket(AF_INET, SOCK_DGRAM, 0);
        if(fd < 0 ) {
                return -ECOMM;
        }

errno=0;
        edata.cmd = LINKTEST_GLINK;
        ifr.ifr_data = (caddr_t)&edata;

if(!ioctl(fd, SIOCETHTOOL, &ifr)) {
                if(edata.data) { ltesting.net 
                        fprintf(stdout, "link detected on %s\n", devname);
                        return 0;
                } else {
                        errno=ENONET;
                }
        }

perror("linktest");
        return errno;
}

int
main(int argc, char *argv[])
{
        if(argc != 2) { 
                usage(argv[0]);
        }
        return linktest(argv[1]);
}

*************************************程序4*********************************************************
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

#define  BASE_VALUE 257

int main(int argc,char *argv[])
{
        int mixer_fd=0;
        char *names[SOUND_MIXER_NRDEVICES]=SOUND_DEVICE_LABELS;
        int value,i;

printf("\nusage:%s dev_no.[0..24] value[0..100]\n\n",argv[0]); 
        printf("eg. %s 0 100\n",argv[0]);
        printf("    will change the volume to MAX volume.\n\n");
        printf("The dev_no. are as below:\n");
        for (i=0;i<SOUND_MIXER_NRDEVICES;i++){
                if (i%3==0) printf("\n");
                printf("%s:%d\t\t",names[i],i);
        }
        printf("\n\n");

if (argc<3)
                exit(1);

if ((mixer_fd = open("/dev/mixer",O_RDWR))){ 
                printf("Mixer opened successfully,working...\n");
                value=BASE_VALUE*atoi(argv[2]);

if (ioctl(mixer_fd,MIXER_WRITE(atoi(argv[1])),&value)==0)
                printf("successfully.....");
                else    printf("unsuccessfully.....");
                printf("done.\n");
         }else
                printf("can't open /dev/mixer error....\n"); ltesting.net

exit(0);
}

ioctl函数详细说明(网络)的更多相关文章

  1. ioctl函数详细说明

    本函数影响由fd 参数引用的一个打开的文件. #include<unistd.h> int ioctl( int fd, int request, .../* void *arg */ ) ...

  2. (十)Linux 网络编程之ioctl函数

    1.介绍 Linux网络程序与内核交互的方法是通过ioctl来实现的,ioctl与网络协议栈进行交互,可得到网络接口的信息,网卡设备的映射属性和配置网络接口.并且还能够查看,修改,删除ARP高速缓存的 ...

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

    1.介绍 Linux网络程序与内核交互的方法是通过ioctl来实现的,ioctl与网络协议栈进行交互,可得到网络接口的信息,网卡设备的映射属性和配置网络接口.并且还能够查看,修改,删除ARP高速缓存的 ...

  4. 获取网络接口信息——ioctl()函数与结构体struct ifreq、 struct ifconf

    转载请注明出处:windeal专栏 Linux 下 可以使用ioctl()函数 以及 结构体 struct ifreq  结构体struct ifconf来获取网络接口的各种信息. ioctl 首先看 ...

  5. ioctl函数用法小记

    By francis_hao    Aug 27,2017   UNPV1对ioctl有算是比较详细的介绍,但是,这些request和后面的数据类型是从哪里来的,以及参数具体该如何使用呢?本文尝试在不 ...

  6. 通用js函数集锦<来源于网络/自己> 【一】

    通用js函数集锦<来源于网络/自己>[一] 1.返回一个全地址2.cookie3.验证用户浏览器是否是微信浏览器4.验证用户浏览器是否是微博内置浏览器5.query string6.验证用 ...

  7. Linux系统编程(4)——文件与IO之ioctl函数

    ioctl是设备驱动程序中对设备的I/O通道进行管理的函数.所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率.马达的转速等等.它的参数个数如下:int ioctl(int ...

  8. ioctl函数

    一.函数原型 #include <unistd.h> int ioctl(int fd, int request, .../* void *arg */); 二.和网络相关的请求(requ ...

  9. (笔记)Linux下的ioctl()函数详解

    我这里说的ioctl函数是指驱动程序里的,因为我不知道还有没有别的场合用到了它,所以就规定了我们讨论的范围.写这篇文章是因为我前一阵子被ioctl给搞混了,这几天才弄明白它,于是在这里清理一下头脑. ...

随机推荐

  1. ESXi主机性能问题

    服务器遇到一个问题 百度了下 基本发现是 四路的 windows 服务器的问题. 造成一些 性能降低. 然后查看了下几个虚拟机 的确是设置的4个虚拟插槽 根据百度的结果 要么改配置文件 要么改 这个四 ...

  2. [转帖] Linux 下面栈空间大小的实验

    比如局部变量是保存在栈空间中的,今天突然在想栈的上限是多大呢,什么时候才会栈溢出? ulimit 命令 linux下使用ulimit 命令可以查看系统的很多上限值. ulimit -a 查看所有 ul ...

  3. CentOS下搭建Hadoop

    目录 安装配置jdk 安装Hadoop 下载解压 配置文件 启动hadoop 格式化HDFS 停止hdfs和yarn 参考:Hadoop官网文档 版本:hadoop-3.2.0 安装配置jdk 因ha ...

  4. IntelliJ IDEA中文乱码问题

    转自  https://blog.csdn.net/m0_37893932/article/details/78280663 1 file->settings->appearence里面有 ...

  5. 洛谷P13445 [USACO5.4]奶牛的电信Telecowmunication(网络流)

    题目描述 农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流.这些机器用如下的方式发送电邮:如果存在一个由c台电脑组成的序列a1,a2,...,a(c),且a1与a2相 ...

  6. ssm 整合 redis(简单教程)

    最后我建议大家使用 Spring StringRedisTemplate 配置,参阅: http://blog.csdn.net/hanjun0612/article/details/78131333 ...

  7. 【题解】 bzoj1597: [Usaco2008 Mar]土地购买 (动态规划+斜率优化)

    bzoj1597懒得复制,戳我戳我 Solution: 线性DP打牌\(+\)斜率优化 定义状态:\(dp[i]\)到了位置\(i\)最少花费 首先我们要发现,如果有一个小方块能被其他的大方块包围,其 ...

  8. 5: EL 表达式小结

    1.EL表达式的语法格式很简单: 以前编写jsp代码时,如果要获取表单中的用户名,一般使用  <%=request.getParameter("name")%> ,这样 ...

  9. 《剑指offer》— JavaScript(30)连续子数组的最大和

    连续子数组的最大和 题目描述 HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好 ...

  10. 基础知识--:before伪元素和:after伪元素

    http://book.51cto.com/art/201108/285688.htm 3.7  替换指定位置 大家都知道before和after是前.后的意思.但是奇怪的是,CSS中的:before ...