fcntl函数的简单应用

fcntl函数原型如下:
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);

相关的参数简单介绍如下:
其中参数fd表示将要设置的文件描述符,参数cmd表示欲操作的命令。
第三个参数总是一个整数,与上面所示函数原型中的注释部分相对应。但是在作为记录锁用时,第三个参数则是指向一个结构的指针。
   fcntl函数有5种功能(取决于cmd的取值):
     1.复制一个现有的描述符(cmd=F_DUPFD).
     2.获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
     3.获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
     4.获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
     5.获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW).
 用fcntl改变File Status Flag

#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define MSG_TRY "try again/n"

int main(void)
{
 char buf[10];
 int n;
 int flags;
 flags = fcntl(STDIN_FILENO, F_GETFL);
 flags |= O_NONBLOCK;
 if (fcntl(STDIN_FILENO, F_SETFL, flags) == -1) {
  perror("fcntl");
  exit(1);
 }
tryagain:
 n = read(STDIN_FILENO, buf, 10);
 if (n < 0) {
  if (errno == EAGAIN) {
   sleep(1);
   write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
   goto tryagain;
  }
  perror("read stdin");
  exit(1);
 }
 write(STDOUT_FILENO, buf, n);
 return 0;
}


以下程序通过命令行的第一个参数指定一个文件描述符,同时利用Shell的重定向功能在该描述符上打开文件,然后用fcntl 的F_GETFL 命令取出File Status Flag并打印。

#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
 int val;
 if (argc != 2) {
  fputs("usage: a.out <descriptor#>/n", stderr);
  exit(1);
 }
 if ((val = fcntl(atoi(argv[1]), F_GETFL)) < 0) {
  printf("fcntl error for fd %d/n", atoi(argv[1]));
  exit(1);
 }
 switch(val & O_ACCMODE) {
 case O_RDONLY:
  printf("read only");
  break;
 case O_WRONLY:
  printf("write only");
  break;
 case O_RDWR:           
  printf("read write");
  break;
 default:
  fputs("invalid access mode/n", stderr);
  exit(1);
 }
 if (val & O_APPEND) 
  printf(", append");
 if (val & O_NONBLOCK)          
  printf(", nonblocking");
 putchar('/n');
 return 0;
}运行该程序的几种情况解释如下。

$ ./a.out 0 < /dev/tty

read onlyShell在执行a.out 时将它的标准输入重定向到/dev/tty ,并且是只读的。argv[1] 是0,因此取出文件描述符0(也就是标准输入)的File Status Flag,用掩码O_ACCMODE 取出它的读写位,结果是O_RDONLY 。注意,Shell的重定向语法不属于程序的命令行参数,这个命行只有两个参数,argv[0] 是"./a.out",argv[1] 是"0",重定向由Shell解释,在启动程序时已经生效,程序在运行时并不知道标准输入被重定向了。

$ ./a.out 1 > temp.foo

$ cat temp.foo

write onlyShell在执行a.out 时将它的标准输出重定向到文件temp.foo ,并且是只写的。程序取出文件描述符1的File Status Flag,发现是只写的,于是打印write only ,但是打印不到屏幕上而是打印到temp.foo 这个文件中了。

$ ./a.out 2 2>>temp.foo

write only, appendShell在执行a.out 时将它的标准错误输出重定向到文件temp.foo ,并且是只写和追加方式。程序取出文件描述符2的File Status Flag,发现是只写和追加方式的。

$ ./a.out 5 5<>temp.foo

read writeShell在执行a.out 时在它的文件描述符5上打开文件temp.foo ,并且是可读可写的。程序取出文件描述符5的File Status Flag,发现是可读可写的。

我们看到一种新的Shell重定向语法,如果在<、>、>>、<>前面添一个数字,该数字就表示在哪个文件描述符上打开文件,例如2>>temp.foo表示将标准错误输出重定向到文件temp.foo并且以追加方式写入文件,注意2和>>之间不能有空格,否则2就被解释成命令行参数了。文件描述符数字还可以出现在重定向符号右边,例如:

$ command > /dev/null 2>&1首先将某个命令command的标准输出重定向到/dev/null ,然后将该命令可能产生的错误信息(标准错误输出)也重定向到和标准输出(用&1标识)相同的文件,即/dev/null ,如下图所示。

图 28.3. 重定向之后的文件描述符表

 重定向之后的文件描述符表

 

/dev/null 设备文件只有一个作用,往它里面写任何数据都被直接丢弃。因此保证了该命令执行时屏幕上没有任何输出,既不打印正常信息也不打印错误信息,让命令安静地执行,这种写法在Shell脚本中很常见。注意,文件描述符数字写在重定向符号右边需要加&号,否则就被解释成文件名了,2>&1其中的>左右两边都不能有空格。

除了F_GETFL 和F_SETFL 命令之外,fcntl 还有很多命令做其它操作,例如设置文件记录锁等。可以通过fcntl 设置的都是当前进程如何访问设备或文件的访问控制属性,例如读、写、追加、非阻塞、加锁等,但并不设置文件或设备本身的属性,例如文件的读写权限、串口波特率等。下一节要介绍的ioctl 函数用于设置某些设备本身的属性,例如串口波特率、终端窗口大小,注意区分这两个函数的作用。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值