ioctrl函数, socket函数

ioctrl函数, socket函数[1]
2010-03-02 18:09

ioctl函数

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

#include<unistd.h>

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

返回0 :成功    -1 :出错

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

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

套接口操作

文件操作

接口操作

ARP 高速缓存操作

路由表操作

流系统

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

类别/ Request/ 说明/ 数据类型

套接口

SIOCATMARK

是否位于带外标记

int

SIOCSPGRP

设置套接口的进程ID 或进程组ID

int

SIOCGPGRP        

获取套接口的进程ID 或进程组ID

int

                

文件

FIOASYNC

设置/清除信号驱动异步I/O标志

int

FIONREAD        

获取接收缓存区中的字节数

int

FIOSETOWN        

设置文件的进程ID或进程组ID        

int

FIOGETOWN        

获取文件的进程ID或进程组ID

int

FIONBIN        

设置/清除非阻塞I/O标志

int

接口

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

获取接口MTU

struct ifreq

SIOCxxx

还有很多取决于系统的实现


ARP

SIOCSARP

创建/修改ARP表项

struct arpreq

SIOCGARP

获取ARP表项

struct arpreq

SIOCDARP

删除ARP表项

struct arpreq

                

路由

SIOCADDRT

增加路径        

struct rtentry

SIOCDELRT

删除路径        

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

结构,如下所示:

(略)

再调用ioctl 前我们必须先分撇一个缓冲区和一个ifconf 结构,然后才初始化后者。如下图

展示了一个ifconf 结构的初始化结构,其中缓冲区的大小为1024 ,ioctl 的第三个参数指向

这样一个ifconf 结构。

ifc_len         1024

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

假设内核返回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之外的新的定义,例如,WaveLAN无线网络卡会保..........(还有很多内容,在此略过)

socket函数:

int socket(int domain,int type, int protocol);

domain:表示所使用的协议族;

type:表示套接口的类型;

protocol:表示所使用的协议族中某个特定的协议。

如果函数调用成功,套接口的描述符(非负整数)就作为函数的返回值,假如返回值为-1,就表明有错误发生。

利用socket函数来获取网卡MAC信息时,domain参数取值AF_INET,表示采用internet协议族;type参数指定为SOCK_DGRAM,表示采用数据报类型套接口,protocol参数在这种组合下只有唯一选择,故用0填充。

I/O控制函数ioctl用于对文件进行底层控制,这里的文件包含网卡、终端、磁带机、套接口等软硬件设施,实际的操作来自各个设备自己提供的ioctl接口。ioctl函数的原型如下:

int ioctl(int d,int request,…)

这里,参数d取值套接口的描述符,第一个request参数指定通过socket传输的I/O类型。本实验可以取值 SIONGIFHWADDR(0x8927),表示取硬件地址。其他取值及其含义详见/usr/includr/linux/sockios.h。其后的 request参数用于为实现I/O控制所必须传入或传出的参数。本实验需要用ifr结构传入网卡设备名,并传出6B的MAC地址。

socket简介:

所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求

以J2SDK-1.3为例,Socket和ServerSocket类库位于java.net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。

用ioctl获得本地ip地址时要用到两个结构体ifconf和ifreq,它们对于大多数人
来说都是比较陌生的,这里给大家一种比较简单的理解方法,当然只一种帮助
理解的方法,在描述中可能会有一些地方与真实定义有所出入,仅供参考.

首先先认识一下ifconf和ifreq:

//ifconf通常是用来保存所有接口信息的


//if.h


struct

ifconf {    int


    ifc_len;            /* size of buffer    */


    union     {      char

*ifcu_buf;                        /* input from user->kernel*/


      struct

ifreq *ifcu_req;        /* return from kernel->user*/


    } ifc_ifcu;};#define


    ifc_buf    ifc_ifcu.ifcu_buf        /* buffer address    */


#define


    ifc_req    ifc_ifcu.ifcu_req        /* array of structures    */


//ifreq用来保存某个接口的信息


//if.h


struct
ifreq 
{   char
ifr_name[IFNAMSIZ];   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#define
ifr_dstaddr ifr_ifru.ifru_dstaddr#define
ifr_broadaddr ifr_ifru.ifru_broadaddr
上边这两个结构看起来比较复杂,我们现在把它们简单化一些:
比如说现在我们向实现获得本地IP的功能。

我们的做法是:
1. 先通过ioctl获得本地所有接口的信息,并保存在ifconf中
2. 再从ifconf中取出每一个ifreq中表示ip地址的信息

具体使用时我们可以认为ifconf就有两个成员:
ifc_len 和 ifc_buf, 如图一所示:

  

ifc_len:表示用来存放所有接口信息的缓冲区长度
ifc_buf:表示存放接口信息的缓冲区

所以我们需要在程序开始时对ifconf的ifc_len和ifc_buf进行初始化 
接下来使用ioctl获取所有接口信息,完成后ifc_len内存放实际获得的借口信息总长度
并且信息被存放在ifc_buf中。 
如下图示:(假设读到两个接口信息)

接下来我们只需要从一个一个的接口信息获取ip地址信息即可。

下面有一个简单的参考:

#include #include #include #include #include in
.h>#include <string
.h>#include if
.h>#include int
main(){    int
i=0;    int
sockfd; struct
ifconf ifconf; unsigned char
buf[512]; struct
ifreq *ifreq;    //初始化ifconf


ifconf.ifc_len = 512; ifconf.ifc_buf = buf;      if
((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0)    {        perror("socket"
);        exit(1);    }    ioctl(sockfd, SIOCGIFCONF, &ifconf);    //获取所有接口信息


    //接下来一个一个的获取IP地址


ifreq = (struct
ifreq*)buf;    for
(i=(ifconf.ifc_len/sizeof
(struct
ifreq)); i>0; i--) {//      if(ifreq->ifr_flags == AF_INET){            //for ipv4


          printf("name = [%s]\n"
, ifreq->ifr_name);      printf("local addr = [%s]\n"
,inet_ntoa(((struct
sockaddr_in*)&(ifreq->ifr_addr))->sin_addr));      ifreq++;// }


}    return
0;}

转载于:https://my.oschina.net/u/147624/blog/41780

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值