fcntl函数-文件控制函数

今日命令在vim中使用:vsplit ./include/io.h
是以垂直方式打开io.h文件
同理:split ./include/io.h
是以水平方式打开io.h文件

可以用fcntl 函数改变一个已打开的文件的属性,可以重新设置读、写、追加、非阻塞等标志(这些标志称为File StatusFlag),而不必重新open 文件。

#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);

这个函数和open 一样,也是用可变参数实现的,可变参数的类型和个数取决于前面的cmd 参数。


针对第2个参数,int cmd fcntl函数有五种功能:
• 复制一个现存的描述符(cmd=F_DUPFD)    。
• 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD)   。
• 获得/设置文件状态标志(cmd=F_GETFL或F_SETFL) 。
• 获得/设置异步I/O有权(cmd=F_GETOWN或F_SETOWN) 。
• 获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW)。

我们将涉及与进程表项中各文件描述符相关联的文件描述符标志, 以及每个文件表项中的文件状态标志,

一~复制文件描述符
• F_DUPFD 复制文件描述符filedes,新文件描述符作为函数值返回。它是尚未打开的各
描述符中大于或等于第三个参数值(取为整型值)中各值的最小值。新描述符与 filedes 共享同
一文件表项。但是,新描述符有它自己的一套文件描述符标志,其 F D _ C L O E X E C
文件描述符标志则被清除。
• F_GETFD 对应于filedes 的文件描述符标志作为函数值返回。当前只定义了一个文件描
述符标志FD_CLOEXEC。
• F_SETFD 对于filedes 设置文件描述符标志。新标志值按第三个参数 (取为整型值)设置。
应当了解很多现存的涉及文件描述符标志的程序并不使用常数 F D _ C L O E X E C,而是将此
标志设置为0(系统默认,在exec时不关闭)或1(在exec时关闭)。

二~文件描述符号,套接口 属性相关
• F_GETFL 对应于filedes 的文件状态标志作为函数值返回。在说明 open函数时,已说明
了文件状态标志   不幸的是,三个存取方式标志 (O_RDONLY,O_WRONLY,以及O_RDWR)并不各占1位。(正
如前述,这三种标志的值各是 012,由于历史原因。这三种值互斥 — 一个文件只能有这
三种值之一。 )因此首先必须用屏蔽字 O_ACCMODE相与 取得存取方式位,然后将结果与这三种值
相比较。
• F_SETFL 将文件状态标志设置为第三个参数的值 (取为整型值)。 可以更改的几个标志是:
O_APPEND,O_NONBLOCK,O_SYNC和O_ASYNC。

fcntl的文件状态标志共有7个,O_RDONLY,O_WRONLY,O_RDWR,O_APPEND,O_NONBLOCK,O_SYNC和O_ASYNC


三~信号驱动I/O , 带外数据,设置套接口接受信号的属主
SIGIO,跟信号驱动I/O有关
SIGURG, 和接受带外数据有关
• F_GETOWN 取当前接收SIGIO和SIGURG信号的进程ID或进程组ID。12.6.2节将论述这
两种4.3+BSD异步I/O信号。
• F_SETOWN 设置接收SIGIO和SIGURG信号的进程ID或进程组ID。正的arg指定一个进
程ID,负的arg表示等于arg绝对值的一个进程组ID。
struct flock
{
    short_l_type;    /*锁的类型*/
    short_l_whence;  /*偏移量的起始位置:SEEK_SET,SEEK_CUR,SEEK_END*/
    off_t_l_start;     /*加锁的起始偏移*/
    off_t_l_len;    /*上锁字节*/
    pid_t_l_pid;   /*锁的属主进程ID */
}; 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    pid_t pid;
    //以追加的形式打开文件
    int fd = fd = open("test.txt", O_TRUNC | O_RDWR | O_APPEND | O_CREAT, 0777);
    if(fd < 0)
    {
        perror("open");
        return -1;
    }
    printf("fd = %d\n", fd);

    fcntl(fd, F_SETFD, 0);//关闭fd的close-on-exec标志

    write(fd, "hello c program\n", strlen("hello c program!\n"));

    pid = fork();
    if(pid < 0)
    {
            perror("fork");
            return -1;
    }
    if(pid == 0)
    {
        printf("fd = %d\n", fd);

        int ret = execl("./main", "./main", (char *)&fd, NULL);
        if(ret < 0)
        {
            perror("execl");
            exit(-1);
        }
        exit(0);
    }

    wait(NULL);

    write(fd, "hello c++ program!\n", strlen("hello c++ program!\n"));

    close(fd);

    return 0;
}

main函数

int main(int argc, char *argv[])
{
    int fd = (int)(*argv[1]);//描述符

    printf("fd = %d\n", fd);

    int ret = write(fd, "hello linux\n", strlen("hello linux\n"));
    if(ret < 0)
    {
        perror("write");
        return -1;
    }

    close(fd);

    return 0;
}

用命令F_GETFL和F_SETFL设置文件标志,比如阻塞与非阻塞

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

/**********************使能非阻塞I/O********************
*int flags;
*if(flags = fcntl(fd, F_GETFL, 0) < 0)
*{
*    perror("fcntl");
*    return -1;
*}
*flags |= O_NONBLOCK;
*if(fcntl(fd, F_SETFL, flags) < 0)
*{
*    perror("fcntl");
*    return -1;
*}
*******************************************************/

/**********************关闭非阻塞I/O******************
flags &= ~O_NONBLOCK;
if(fcntl(fd, F_SETFL, flags) < 0)
{
    perror("fcntl");
    return -1;
}
*******************************************************/

int main()
{
    char buf[10] = {0};
    int ret;
    int flags;

    //使用非阻塞io
    if(flags = fcntl(STDIN_FILENO, F_GETFL, 0) < 0)
    {
        perror("fcntl");
        return -1;
    }
    flags |= O_NONBLOCK;
    if(fcntl(STDIN_FILENO, F_SETFL, flags) < 0)
    {
        perror("fcntl");
        return -1;
    }

    while(1)
    {
        sleep(2);
        ret = read(STDIN_FILENO, buf, 9);
        if(ret == 0)
        {
            perror("read--no");
        }
        else
        {
            printf("read = %d\n", ret);
        }

        write(STDOUT_FILENO, buf, 10);
        memset(buf, 0, 10);
    }

    return 0;
}
struct flcok

{

   short int l_type; /* 锁定的状态*/

    //这三个参数用于分段对文件加锁,若对整个文件加锁,则:l_whence=SEEK_SET,l_start=0,l_len=0;

   short int l_whence;/*决定l_start位置*/

   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 以文件结尾为锁定的起始位置。
#include "filelock.h"

/* 设置一把读锁 */
int readLock(int fd, short start, short whence, short len) 
{
    struct flock lock;
    lock.l_type = F_RDLCK;
    lock.l_start = start;
    lock.l_whence = whence;//SEEK_CUR,SEEK_SET,SEEK_END
    lock.l_len = len;
    lock.l_pid = getpid();
//  阻塞方式加锁
    if(fcntl(fd, F_SETLKW, &lock) == 0)
        return 1;

    return 0;
}

/* 设置一把读锁 , 不等待 */
int readLocknw(int fd, short start, short whence, short len) 
{
    struct flock lock;
    lock.l_type = F_RDLCK;
    lock.l_start = start;
    lock.l_whence = whence;//SEEK_CUR,SEEK_SET,SEEK_END
    lock.l_len = len;
    lock.l_pid = getpid();
//  非阻塞方式加锁
    if(fcntl(fd, F_SETLK, &lock) == 0)
        return 1;

    return 0;
}
/* 设置一把写锁 */
int writeLock(int fd, short start, short whence, short len) 
{
    struct flock lock;
    lock.l_type = F_WRLCK;
    lock.l_start = start;
    lock.l_whence = whence;
    lock.l_len = len;
    lock.l_pid = getpid();

    //阻塞方式加锁
    if(fcntl(fd, F_SETLKW, &lock) == 0)
        return 1;

    return 0;
}

/* 设置一把写锁 */
int writeLocknw(int fd, short start, short whence, short len) 
{
    struct flock lock;
    lock.l_type = F_WRLCK;
    lock.l_start = start;
    lock.l_whence = whence;
    lock.l_len = len;
    lock.l_pid = getpid();

    //非阻塞方式加锁
    if(fcntl(fd, F_SETLK, &lock) == 0)
        return 1;

    return 0;
}

/* 解锁 */
int unlock(int fd, short start, short whence, short len) 
{
    struct flock lock;
    lock.l_type = F_UNLCK;
    lock.l_start = start;
    lock.l_whence = whence;
    lock.l_len = len;
    lock.l_pid = getpid();

    if(fcntl(fd, F_SETLKW, &lock) == 0)
        return 1;

    return 0;
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("usage: a.out <fd>\n");
        exit(1);
    }

    int val = 0;
    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:
        printf("invalid access mode\n");
        exit(1);
    }

    if (val & O_APPEND)
        printf(", append");
    if (val & O_NONBLOCK)
        printf(", nonblocking");
    printf("\n");

    return 0;
}
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)
        {
            printf("fcntl F_GETFL error");
            exit(1);
        }

    val |= flags;        /* turn on flags */
 //重新设置文件状态标志(val为新文件的文件状态标志)
    if (fcntl(fd, F_SETFL, val) < 0)
        {
            printf("fcntl F_SETFL error");
            exit(1);
        }
}

void
clr_fl(int fd, int flags)
{
    int val;

    if ((val = fcntl(fd, F_GETFL, 0)) == -1)
    {
        syslog(LOG_ERR, __FILE__, __LINE__,"fcntl() error : %s", strerror(errno));
        exit(1);
    }
    val &= ~flags; /* turn flags off */

    if (fcntl(fd, F_SETFL, val) == -1)
    {
        syslog(LOG_ERR, __FILE__, __LINE__,"fcntl() error : %s", strerror(errno));
        exit(1);
    }
    return;
}

猜你喜欢

转载自blog.csdn.net/andrewgithub/article/details/81585485