嵌入式 浅谈fcntl与ioctl函数

本文深入探讨了嵌入式系统中fcntl和ioctl函数的使用,特别是它们在网络相关操作中的应用。fcntl主要涉及文件描述符的非阻塞IO和信号驱动异步IO等设置,而ioctl则用于接口操作,如设置IP地址、接口标志等。通过示例代码,文章展示了如何使用这两个函数来实现类似于ifconfig命令的功能。
摘要由CSDN通过智能技术生成

fcntl:

#include <sys/ioctl.h>
ioctl函数提供对连接到fd的设备驱动程序的属性和操作的访问
其原型为
extern int ioctl(int fd,unsigned long int request[,char * arg ....])
fd 是打开设备的描述符  request 是函数代码(类似特定的操作一样,这是与设备相关的)
arg  是参数  可选的
返回值是 失败 -1  并设置 errno
成功一般是0  但是任然要视具体情况而定
因为有些属性需要使用返回值 这时不一定是0了
void prinft_screen_dimension(int fd)
{
  int  fd;  //
  struct winsize buf;

  if (ioctl( fd, TIOCGWINZ,&buf ) != -1){
   printf("%d rows x %d cols\n",buf.ws_row,buf.ws_col);
   printf("%d wide x %d tall\n",buf.ws_xpixel,buf.ws_ypixel);
  }
}
每种设备都有自己所支持的设备属性集以及ioctl操作集
fcntl  是用来设置和修改描述符的的属性
一般来说我们对文件的写入都是带有缓冲的,
但是在数据比较重要的时候担心意外事故导致缓冲数据丢失
这时我们可以设置数据存入是同步的(即关闭缓冲属性)
描述符的属性被编码到一个整数中了
fcntl通过读写该整数位来设置文件描述符的属性。
使用fcntl取得此值  修改后 再用fcntl写回

#include <fcntl.h>
fcntl 原型为 
extern int fcntl(int fd, int _cmd,... )

调用形式有
fcntl(int fd,int cmd);
fcntl(int fd,int cmd,long arg)
fcntl(int fd,int cmd,struct flock *lock)
fd 值相应的描述符,cmd 是指相应的操作 
相应操作可以查看man fcntl  会发现fcntl不只会干这些哟。

这里我们用fcntl进行演示(关闭fd的缓冲属性 注意只有块设备与实际文件有这个属性)
int fd,va;

va = fcntl( fd,F_GETFD);
va | = O_SYNC;
fcntl( fd,F_SETFD,va);

当然也可以直接在open的同时进行设置。
不过open的属性设置没有用fcntl那样灵活。
 
注:其中cmd主要包括:
参数fd代表欲设置的文件描述符。
参数cmd代表打算操作的指令。
有以下几种情况:
F_DUPFD用来查找大于或等于参数arg的最小且仍未使用的文件描述词,并且复制参数fd的文件描述词。执行成功则返回新复制的文件描述词。新描述符与fd共享同一文件表项,但是新描述符有它自己的一套文件描述符标志,其中FD_CLOEXEC文件描述符标志被清除。请参考dup2()。
F_GETFD取得close-on-exec旗标。若此旗标的FD_CLOEXEC位为0,代表在调用exec()相关函数时文件将不会关闭。
F_SETFD 设置close-on-exec 旗标。该旗标以参数arg 的FD_CLOEXEC位决定。
F_GETFL 取得文件描述词状态旗标,此旗标为open()的参数flags。
F_SETFL 设置文件描述词状态旗标,参数arg为新旗标,但只允许O_APPEND、O_NONBLOCK和O_ASYNC位的改变,其他位的改变将不受影响。
F_GETLK 取得文件锁定的状态。
F_SETLK 设置文件锁定的状态。此时flcok 结构的l_type 值必须是F_RDLCK、F_WRLCK或F_UNLCK。如果无法建立锁定,则返回-1,错误代码为EACCES 或EAGAIN。
F_SETLKW F_SETLK 作用相同,但是无法建立锁定时,此调用会一直等到锁定动作成功为止。若在等待锁定的过程中被信号中断时,会立即返回-1,错误代码为EINTR。
参数lock指针为flock 结构指针,定义如下
struct flock
{
short int l_type;
short int l_whence;
off_t l_start;
off_t l_len;
pid_t l_pid;
};
l_type 有三种状态:
F_RDLCK 建立一个供读取用的锁定
F_WRLCK 建立一个供写入用的锁定
F_UNLCK 删除之前建立的锁定
l_whence 也有三种方式:
SEEK_SET 以文件开头为锁定的起始位置。
SEEK_CUR 以目前文件读写位置为锁定的起始位置
SEEK_END 以文件结尾为锁定的起始位置。
l_start 表示相对l_whence位置的偏移量,两者一起确定锁定区域的开始位置。
l_len表示锁定区域的长度,若果为0表示从起点(由l_whence和 l_start决定的开始位置)开始直到最大可能偏移量为止。即不管在后面增加多少数据都在锁的范围内。
返回值 成功则返回0,若有错误则返回-1,错误原因存于errno.
fcntl()用来操作文件描述符的一些特性。fcntl 不仅可以施加建议性锁,还可以施加强制锁。同时,fcntl还能对文件的某一记录进行上锁,也就是记录锁。
fcntl的返回值与命令有关。如果出错,所有命令都返回-1,如果成功则返回某个其他值。下列四个命令有特定返回值:F_DUPFD、F_GETFD、F_GETFL、F_GETOWN.第一个返回新的文件描述符,接下来的两个返回相应标志,最后一个返回一个正的进程ID或负的进程组ID。
 
ioctl:

#include<unistd.h>

int ioctl( int fd, int  request, .../* void *arg */ );                              返回0——成功, -1——出错

第一个参数 fd 指示某个文件描述符(当然也包括 套接口描述符)

第二个参数 request 指示要ioctl执行的操作

第三个参数 总是某种指针,具体的指向类型依赖于 request 参数


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

      套接口操作

      文件操作

      接口操作

      ARP 高速缓存操作

      路由表操作

      流系统

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

 
类别       request         说明             (第三个参数)数据类型


        SIOCATMARK   是否位于带外标记               int

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

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


文件     FIONBIO     设置/清除非阻塞IO标识           int

        FIOASYNC    设置/清除信号驱动异步IO标识      int

        FIONREAD    获取接收缓冲区中的字节数         int

                        ……


       SIOCGIFCONF   获取所有接口的清单         struct ifconf

接口    SIOCSIFADDR   设置接口的ip地址          struct ifreq

       SIOCGIFADDR    获取接口地址             struct ifreq

       SIOCSIFFLAGS   设置接口标识             struct  ifreq

       SIOCGIFFLAGS   获取接口标识             struct ifreq

       SIOCSIFDSTADDR 设置点到点地址           struct ifreq

       SIOCGIFDSTADDR 获取点到点地址           struct  ifreq

       SICSIFBRDADDR  设置广播地址             struct ifreq

       SICGIFBRDADDR  获取广播地址             struct ifreq

                        ……


       SIOCSARP    创建/修改ARP表项           struct arpreq

ARP    SIOCGARP     获取ARP表项              struct arpreq

       SIOCDARP     删除ARP表项              struct arpreq


路由                  ……


有很多request请求没有列出,而且不同的系统所提供的request也有所不同,比如linux就不提供SIOCGSIZIFCONF请求)

上面的表中,用ioctl执行接口操作的请求时,要用到结构体 struct ifconf 与 struct ifreq

struct ifconf{

    int ifc_len;                 // 缓冲区ifcu_buf的大小

    union{

        caddr_t ifcu_buf;            // 其实就是char *类型。

        struct ifreq *ifcu_req;    // 为ifconf分配空间时我们用ifcu_buf指针;当要取得或设置该缓冲区中的ifreq类型时,则用这个指针

    }ifc_ifcu;

};

#define  ifc_buf  ifc_ifcu.ifcu_buf    //buffer address

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

struct ifreq
{
    char ifrn_name[IFNAMSIZ];  /* if name, e.g. "eth0"  */
    union {
         struct sockaddr ifru_addr;
          struct sockaddr ifru_dstaddr;
         struct sockaddr  ifru_broadaddr;
         struct sockaddr ifru_netmask;
         struct   sockaddr ifru_hwaddr;
          short ifru_flags;
         int ifru_ivalue;
          int ifru_mtu;
         struct  ifmap ifru_map;
          char ifru_slave[IFNAMSIZ]; /* Just fits the size */
          char ifru_newname[IFNAMSIZ];
         void * ifru_data;
          struct if_settings ifru_settings;
    } ifr_ifru;
};

#define ifr_name ifr_ifrn.ifrn_name                           /* interface  name  */
#define ifr_hwaddr ifr_ifru.ifru_hwaddr                    /* MAC  address   */
#define ifr_addr ifr_ifru.ifru_addr                               /* address  */
#define ifr_dstaddr ifr_ifru.ifru_dstaddr                     /* other end of p-p  lnk */
#define ifr_broadaddr ifr_ifru.ifru_broadaddr            /* broadcast  address */
#define ifr_netmask ifr_ifru.ifru_netmask                  /*  interface net  mask */
#define ifr_flags ifr_ifru.ifru_flags                              /*  flags  */
#define ifr_metric ifr_ifru.ifru_ivalue                          /*  metric  */
#define ifr_mtu  ifr_ifr

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值