设为首页 收藏本站
查看: 931|回复: 2

[经验分享] linux系统编程之文件与I0:文件描述符相关操作-dup,dup2,fcntl

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2013-7-12 09:10:43 | 显示全部楼层 |阅读模式

本节目标:

1,文件共享
  • 打开文件内核数据结构
  • 一个进程两次打开同一个文件
  • 两个进程打开同一个文件
2,复制文件描述符(dup、dup2、fcntl)

一,文件共享

1,一个进程打开两个文件内核数据结构

7547481_13735532400eVw.jpg

说明:

文件描述符表:每个进程都有一张,彼此独立,每个文件描述符表项都指向一个文件表,文件描述符0(STDIN_FILENO)、1(STDOUT_FILENO)、2(STDERR_FILENO),默认已经打开,分别表示:标准输入,标准输出,标准错误设备。

文件表:每打开一个文件就对应一张文件表,文件表可以共享,当多个文件描述符指向同一个文件表时,文件表中的

refcnt字段会相应变化。文件状态标识:文件的打开模式(R,W,RW,APPEND,NOBLOCK,等),当前文件偏移量,refcnt:被引用数量,

v节点指针:指向一个v节点表。

v节点表:每个文件对应一个,无论被被多少个进程打开都只有一个,它包括v节点信息(主要是stat结构体中的信息),i节点信息。

每个进程默认只能打开1024个文件描述符,当一个进程打开一个文件时,默认会从0开始查找未被使用的描述符,由于0,1,2默认被占用,所有一般从3开始使用。

2、一个进程两次打开同一个文件

7547481_13735532428FoM.jpg

当一个进程多次打开同一个文件时,首先会在描述符表顺序查找未被使用的描述符,然后每打开一次建立一张文件表,但各文件表中的v节点指针都指向同一个v节点表。

示例程序:

#include <unistd.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#define ERR_EXIT(m) \    do \    { \        perror(m); \        exit(EXIT_FAILURE); \    } while(0)int main(int argc, char *argv[]){    int fd1;    int fd2;    char buf1[1024] = {0};    char buf2[1024] = {0};    fd1 = open("test.txt", O_RDONLY);    if (fd1 == -1)        ERR_EXIT("open error");    read(fd1, buf1, 5);    printf("buf1=%s\n", buf1);        fd2 = open("test.txt", O_RDWR);    if (fd2 == -1)        ERR_EXIT("open error");    read(fd2, buf2, 5);    printf("buf2=%s\n", buf2);    write(fd2, "AAAAA", 5);    memset(buf1, 0, sizeof(buf1));    read(fd1, buf1, 5);    printf("buf1=%s\n", buf1);    close(fd1);    close(fd2);    return 0;}

运行结果:

7547481_1373553242tOYz.jpg

说明:先创建test.txt文件写入hello,再同一个进程两次打开该文件,可见每打开一次文件就参数一张文件表,不共享偏移量,都开始位置读取,之后利用第二个文件描述符写入AAAAA,在利用第一个描述符可以读取出,表明都指向同一个v节点表,操作同一个文件。

3,两个不同进程打开同一个文件

7547481_1373553245eJe4.jpg

当不同进程打开同一个文件时,每个进程首先在它们各自的文件描述符表中顺序查找未被使用的描述符,最终获得的文件描述符可能相同也可能不同,每个fd指向各自的文件表,但同样,每个文件表中的v节点指针都指向同一个v节点表。


二、复制文件描述符

复制前:

7547481_1373553245xzfQ.jpg


复制后:

7547481_1373553246b8LO.jpg

复制后,两个文件描述符都指向了同一个文件表,refcnt=2。

复制文件描述符有三种方法:

1,dup

2,dup2

#include <unistd.h>

int dup(int oldfd);
int dup2(int oldfd, int newfd);

DESCRIPTION
       These system calls create a copy of the file descriptor oldfd.

       dup()  uses  the lowest-numbered unused descriptor for the new descriptor.

       dup2() makes newfd be the copy of oldfd, closing newfd first if  necessary, but note

                  the following:

       *  If  oldfd  is  not a valid file descriptor, then the call fails, and newfd is not closed.

       *  If oldfd is a valid file descriptor, and newfd has the same value as
          oldfd, then dup2() does nothing, and returns newfd.

       After  a  successful return from one of these system calls, the old and new file descriptors may be used interchangeably.  They  refer  to  the same open file description (see open(2)) and thus share file offset and file status flags; for example, if the file offset is modified by using lseek(2)  on one of the descriptors, the offset is also changed for the other.

RETURN VALUE
       On success, these system calls return the new descriptor.  On error, -1 is returned, and errno is set appropriately.

示例程序:

#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <fcntl.h>int main(void){    int fd;    fd = open("test.txt",O_WRONLY);    if( fd == -1){        perror("open error");        exit(EXIT_FAILURE);    }    int fd2;    fd2 = dup(fd);    if(fd2 == -1){        perror("dup error");        exit(EXIT_FAILURE);    }    printf("oldfd = %d\n",fd);    printf("newfd = %d\n",fd2);    int fd3;    close(0); //或者close(STDIN_FILENO)    fd3 = dup(fd);    if(fd3 == -1){        perror("dup error");        exit(EXIT_FAILURE);    }    printf("after close stdin,the newfd = %d\n",fd3);     exit(EXIT_SUCCESS);}

运行结果:

7547481_1373553247015D.jpg

用dup进行文件描述符的复制时,顺序查找即从0开始查找可以文件描述符
示例2:

#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <fcntl.h>int main(void){    int fd;    fd = open("test.txt",O_WRONLY);    if( fd == -1){        perror("open error");        exit(EXIT_FAILURE);    }    int fd2;    fd2 = dup2(fd,0);    if(fd2 == -1){        perror("dup error");        exit(EXIT_FAILURE);    }    printf("oldfd = %d\n",fd);    printf("newfd = %d\n",fd2);    exit(EXIT_SUCCESS);}

运行结果:

7547481_1373553249nVs5.jpg

用dup2进行文件描述符复制时,指定需要复制的新的描述符,如果该描述符已经被占用,则先关闭它在重新复制,类似于先调用close再dup


3,fcntl

功能:操纵文件描述符,改变已打开的文件的属性

#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );

DESCRIPTION
       fcntl() performs one of the operations described below on the open file
       descriptor fd.  The operation is determined by cmd.

       fcntl() can take an optional third argument.  Whether or not this argu-
       ment  is  required is determined by cmd.  The required argument type is
       indicated in parentheses after  each  cmd  name  (in  most  cases,  the
       required  type  is  long,  and  we identify the argument using the name
       arg), or void is specified if the argument is not required.

由第二个参数指定操作类型,后面点的可变参数指定该命令所需的参数

这里我们进行文件描述符复制,可将cmd 设为: F_DUPFD (long),该命令表示:

Find the lowest numbered available file descriptor greater  than
  or  equal to arg
and make it be a copy of fd.  This is different
from dup2(2), which uses exactly the descriptor specified.

  On success, the new descriptor is returned.

示例程序:

#include <unistd.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#define ERR_EXIT(m) \    do \    { \        perror(m); \        exit(EXIT_FAILURE); \    } while(0)int main(int argc, char *argv[]){    int fd;    fd = open("test.txt", O_WRONLY);    if (fd == -1)        ERR_EXIT("open error");    close(1);    if (fcntl(fd, F_DUPFD, 0) < 0)        ERR_EXIT("dup fd error");    printf("-----------\n");//进行重定向,将不会显示在标准输出,    return 0;}

运行结果:

7547481_1373553249lNQd.jpg



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-7418-1-1.html 上篇帖子: linux系统编程之文件与IO:实现ls -l功能 下篇帖子: RHN客户端注册的时候报SSL错误 linux

尚未签到

发表于 2013-9-24 02:34:21 | 显示全部楼层
床上运动也可以减肥的,你们都不知道吗?

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

累计签到:1 天
连续签到:1 天
发表于 2014-1-5 11:40:12 | 显示全部楼层
何必在一起、让我嗳上你。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表