fcntl函数简介
#include<unistd.h>
#include<fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
//改变打开文件的属性
/*
作用:
(1) 复制一个已有的描述符`cmd = F_DUPFD 或者 F_DUPFD_CLOEXEC`
(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`
*/
文件状态标志
文件状态标志 | 说明 |
---|---|
O_RDONLY | 只读 |
O_WRONLY | 只写 |
O_RDWR | 读、写 |
O_EXEC | 只执行 |
O_SEARCH | 只搜索打开目录 |
O_APPEND | 追加 |
O_NONBLOCK | 非阻塞 |
O_SYNC | 等待写完成 |
O_DSYNC | 等待写完成 |
O_RSYNC | 同步读和写 |
O_FSYNC | 等待写完成 |
O_ASYNC | 异步I/O |
获取文件状态标志
#include "apue.h"
#include <fcntl.h>
int
main(int argc, char *argv[])
{
int val;
if (argc != 2)
err_quit("usage: a.out <descriptor#>");
if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
err_sys("fcntl error for fd %d", atoi(argv[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:
err_dump("unknown access mode");
}
if (val & O_APPEND)
printf(", append");
if (val & O_NONBLOCK)
printf(", nonblocking");
if (val & O_SYNC)
printf(", synchronous writes");
#if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC) && (O_FSYNC != O_SYNC)
if (val & O_FSYNC)
printf(", synchronous writes");
#endif
putchar('\n');
exit(0);
}
设置文件状态标志
先调用fcntl
获取文件状态标志,再或等于需要设置的flag
以免关闭以前设置的标志位
#include "apue.h"
#include <fcntl.h>
void
set_fl(int fd, int flags) /* flags are file status flags to turn on */
{
int val;
if ((val = fcntl(fd, F_GETFL, 0)) < 0)
err_sys("fcntl F_GETFL error");
val |= flags; /* turn on flags */
if (fcntl(fd, F_SETFL, val) < 0)
err_sys("fcntl F_SETFL error");
}
dup函数
dup函数,主要是
#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);
拷贝描述符,cgi程序中经常使用dup2的供父子进程进行通信。
//子进程中
dup2(cgi_output[1], 1);
dup2(cgi_input[0], 0);
close(cgi_output[0]);
close(cgi_input[1]);
简单解释一下:
cgi_output 和cgi_input是两个管道0-对应管道读 1对应管道写
而我们知道linux系统默认的描述符0,1,2分别表示读、写、错误
dup2
可以用下述原子操作替代:
close(1);
fcntl(cgi_output[1],F_DUPFD,1)
也就是说写入到标准输出的内容会被重定向到管道,这样父进程就可以通过cgi_output[0]读入CGI程序的输出了,这样就解释了,为啥CGI程序中有大量的print语句。
同理,从管道读取的内容也将作为CGI 程序的标准输入,父进程通过写管道的方式传给CGI程序参数。