ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Linux高级I/O函数 dup, dup2, dup3

2022-04-30 19:02:30  阅读:171  来源: 互联网

标签:CLOEXEC dup3 dup2 int fd2 fd Linux dup include


目录

dup()

如何把标志输入(stdin)重定向到一个文件,或者把标志输出(stdout)重定向到一个网络连接(sockfd)?
可以用系统调用dup或dup2。

#include <unistd.h>

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

dup() 创建一个新fd,和原有fd指向相同的文件、管道或网络连接。dup()返回的文件描述符总是取系统当前可用最小整数值。

示例1

将fd2重定向到fd1。然后,从键盘接收输入,并将内容写入fd2所指文件

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

int main()
{
    int fd = open("test.txt", O_CREAT | O_RDWR | O_TRUNC, 0774);
    if (fd < 0) {
        perror("open error");
        exit(-1);
    }
    int fd2 = dup(fd);
    if (fd2 < 0) {
        perror("dup error");
        exit(-1);
    }
    printf("fd = %d, fd2 = %d\n", fd, fd2); // 通常fd = 3, fd2 = 4, 因为0,1,2分别为标准输入、标准输出、标准错误

    char buf[128];
    ssize_t n;
    /* 从键盘接收输入并写入fd2所指文件 */
    while (( n = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
        if (write(fd2, buf, static_cast<size_t>(n)) < 0) {
            printf("Write error!\n");
            exit(-1);
        }
    }
    return 0;
}

dup2()

dup2和dup类似,区别在于:

  • dup2可以用参数newfd指定新文件描述符的值。
  • 如果newfd已经被使用,则系统会将newfd所指文件关闭;如果newfd等于oldfd,则直接返回newfd,而不关闭newfd所指文件。
  • dup2复制的文件描述符与原来的文件描述符共享各种文件状态,共享所有的锁定、读写位置、各种权限及flags等,但不包括close-on-exec。

成功调用,则返回新创建的文件描述符;失败返回-1,错误保存到errno。

dup2(oldfd, newfd)结果等价于

close(oldfd);
int fd = fcntl(oldfd, F_DUPFD, newfd);

示例2

在dup基础上,做1个小改动:将dup2的newfd指定为fileno(stderr),即值2。可以看到,fd2重定向到了原来stderr所指文件描述符2,而原来的stderr(标准错误)将关闭,而不再能输出错误信息。

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

int main()
{
    int fd = open("test.txt", O_CREAT | O_RDWR | O_TRUNC, 0774);
    if (fd < 0) {
        perror("open error");
        exit(-1);
    }

    int fd2 = dup2(fd, fileno(stderr)); // 2
    if (fd2 < 0) {
        perror("dup error");
        exit(-1);
    }

    printf("fd = %d, fd2 = %d\n", fd, fd2); // fd = 3, fd = 2
    fprintf(stderr, "test stderr\n");

    char buf[128];
    ssize_t n;
    /* 从键盘接收输入并写入fd2所指文件 */
    while (( n = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
        if (write(fd2, buf, static_cast<size_t>(n)) < 0) {
            printf("Write error!\n");
            exit(-1);
        }
    }
    return 0;
}

dup3()

还有一个系统调用dup3,类似于dup2,区别在于:

  • 调用者可以强制为新创建的文件描述符指定close-on-exec标志(open搭配O_CLOEXEC,fcntl搭配FD_CLOEXEC)
  • 如果oldfd等于newfd,调用失败,报错EINVAL。
#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <fcntl.h>              /* Obtain O_* constant definitions */
#include <unistd.h>

int dup3(int oldfd, int newfd, int flags);

示例3

在示例1基础上做下改动:判断fd添加O_CLOEXEC后的选项值,然后清除。对比单独为fd添加FD_CLOEXEC选项,和由dup3指定O_CLOEXEC选项,得到的文件描述符的选项差异。
可以看到,dup3指定O_CLOEXEC选项,跟fcntl指定O_CLOEXEC选项的效果是一样的。

int main()
{
    int fd = open("test.txt", O_CREAT | O_RDWR | O_TRUNC, 0774);
    if (fd < 0) {
        perror("open error");
        exit(-1);
    }
    /* 获得fd的初始flags, 然后添加FD_CLOEXEC选项, 最后清除FD_CLOEXEC选项 */
    int flags0 = fcntl(fd, F_GETFD);
    printf("primary flags of fd is %d\n", flags0);
    fcntl(fd, F_SETFD, flags0 | FD_CLOEXEC);
    int flags1 = fcntl(fd, F_GETFD);
    printf("After adding FD_CLOEXEC, flags of fd is %d\n", flags1);
    flags1 = fcntl(fd, F_SETFD, flags0);
    printf("Restore FD_CLOEXEC(cleared), flags of fd is %d\n", flags1);


    int fd2 = dup3(fd, fileno(stderr), O_CLOEXEC); // 2
    if (fd2 < 0) {
        perror("dup error");
        exit(-1);
    }
    printf("fd = %d, fd2 = %d\n", fd, fd2); // fd = 3, fd = 2

    flags1 = fcntl(fd2, F_GETFD);
    printf("flags of fd2 is %d\n", flags1);

    char buf[128];
    ssize_t n;
    /* 从键盘接收输入并写入fd2所指文件 */
    while (( n = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
        if (write(fd2, buf, static_cast<size_t>(n)) < 0) {
            printf("Write error!\n");
            exit(-1);
        }
    }
    return 0;
}

参考

https://blog.csdn.net/tiandc/article/details/81489447

标签:CLOEXEC,dup3,dup2,int,fd2,fd,Linux,dup,include
来源: https://www.cnblogs.com/fortunely/p/16210932.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有