【linux】dup文件描述符复制函数和管道详解

news2024/11/28 13:38:08

目录

一、文件描述符复制

1、dup函数(复制文件描述符)

​编辑 2、dup2函数(复制文件描述符)

​编辑 二、无名管道pipe

1、概述 

2、无名管道的创建

 3、无名管道读写的特点

 4、无名管道ps -A | grep bash实现

 三、有名管道FIFO(命名管道)

1、概述 

2、创建有名管道 mkfifo

3、有名管道读写的特点


一、文件描述符复制

        让新的文件描述符 指向 旧的文件描述符。(新旧文件描述符指向同一个文件) 使用的函数dup、dup2。

1、dup函数(复制文件描述符)

#include<unistd.h>

int dup(int oldfd);

        dup函数的功能:从系统中寻找最小可用的文件描述符 作为oldfd的副本。 新文件描述符 通过dup的返回值返回。

 2、dup2函数(复制文件描述符)

        #include<unistd.h>

        int dup2(int oldfd, int newfd);  

dup2的功能:将newfd作为oldfd的副本。 如果newfd事先存在 dup2会先close(newfd),然后将newfd作为oldfd的副本。 

 二、无名管道pipe

1、概述 

         管道(pipe)又称无名管道。 无名管道是一种特殊类型的文件,在应用层体现为 两个打开的文件描述符(读端和写端)。

管道的特点:

  1. 半双工,数据在同一时刻只能在一个方向上流动。
  2. 数据只能从管道的一端写入,从另一端读出
  3. 写入管道中的数据遵循先入先出的规则。
  4. 管道所传送的数据是无格式的,这要求管道的读出方与写入方必须事先约定好数据 的格式, 如多少字节算一个消息等。
  5. 管道不是普通的文件,不属于某个文件系统,其只存在于内存
  6. 管道在内存中对应一个缓冲区。不同的系统其大小不一定相同。
  7. 从管道读数据是一次性操作,数据一旦被读走,它就从管道中被抛弃,释放空间以便写更多的数据。
  8. 管道没有名字,只能在具有公共祖先的进程之间使用 

2、无名管道的创建

        #include<unistd.h>

        int pipe(int filedes[2]);

功能:经由参数filedes返回两个文件描述符

参数: filedes为int型数组的首地址,其存放了管道的文件描述符fd[0]、fd[1]。 filedes[0]为读而打开,filedes[1]为写而打开管道,filedes[0]的输出是filedes[1]的输 入。

返回值: 成功:返回 0 失败:返回-1

注意:在使用无名管道的时候 必须事先确定,谁发,谁收的问题。一旦确定不可更改。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
    //创建一个无名管道
    int fd[2];
    pipe(fd);
    //创建一个子进程
    //父进程发 子进程收
    pid_t pid=fork();
    if(pid==0)//子进程
    {
        //子进程的写端无意义(可以事先关闭)
        close(fd[1]);
        //子进程接收父进程消息
        unsigned char buf[128]="";
        printf("子进程%d正在等待父进程的消息\n", getpid());
        read(fd[0],buf,sizeof(buf));
        printf("子进程%d读到的消息为:%s\n", getpid(), buf);
        //子进程读完数据 应该关闭读端
        close(fd[0]);
        //显示退出
        _exit(-1);
    }
    if(pid>0) //父进程
    {
        //父进程的读端无意义(可以事先关闭)
        close(fd[0]);
        //写端写入数据
        printf("3秒后父进程%d写入数据hello pipe\n",getpid());
        sleep(3);
        write(fd[1],"hello pipe",strlen("hello pipe"));
        printf("父进程:%d完成写入\n", getpid());
        //通信完成 应该关闭写端
        close(fd[0]);
        //等待子进程退出
        wait(NULL);
    }
    return 0;
}

 3、无名管道读写的特点

1、默认用read函数从管道中读数据是阻塞的。

2、调用write函数向管道里写数据,当缓冲区已满时write也会阻塞。

3、通信过程中,读端口全部关闭后,写进程向管道内写数据时,写进程会(收 到SIGPIPE信号)退出。 

 4、无名管道ps -A | grep bash实现

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
    //创建一个无名管道
    int fd[2];
    pipe(fd);
    //创建两个子进程
    int i=0; 
    for(i=0;i<2;i++)
    {
        pid_t pid=fork();
        if(pid==0)
            break;//防止子进程继续创建子进程
    }
    if(i==0)//子进程1
    {
        //ps ‐A 写端
        close(fd[0]);
        //1作为fd[1]的副本
        dup2(fd[1],1);
        //执行ps ‐A
        execlp("ps","ps","-A",NULL);
        _exit(-1);
    }
    else if(i==1)//子进程2
    {
        //grep bash 读端
        close(fd[1]);
        //0作为fd[0]的副本
        dup2(fd[0],0);
        //执行grep bash
        execlp("grep","grep","bash",NULL);
    }
    if(i==2) //父进程
    {
        //关闭管道读写端
        close(fd[0]);
        close(fd[1]);
        while(1)
        {
            pid_t pid=waitpid(-1,NULL,WNOHANG);
            if(pid>0)
                printf("子进程%d退出了\n", pid);
            else if(pid==0)
                continue;
            else if(pid<0)
                break;
        }
    }
    return 0;
}

 三、有名管道FIFO(命名管道)

1、概述 

         主要用于没有血缘关系的进程间通信。

 

 特点:

  1. 半双工,数据在同一时刻只能在一个方向上流动。
  2. 写入FIFO中的数据遵循先入先出的规则。
  3. FIFO所传送的数据是无格式的,这要求FIFO的读出方与写入方必须事先 约定好数据的格式,如多少字节算一个消息等。
  4. FIFO在文件系统中作为一个特殊的文件而存在,但FIFO中的内容存放在内存中。
  5. 管道在内存中对应一个缓冲区。不同的系统其大小不一定相同
  6. 从FIFO读数据是一次性操作,数据一旦被读,它就从FIFO中被抛弃,释 放空间以便写更多的数据。
  7. 当使用FIFO的进程退出后,FIFO文件将继续保存在文件系统中以便以后使用。
  8. FIFO有名字不相关的进程可以通过打开命名管道进 行通信(重要)

2、创建有名管道 mkfifo

FIFO文件的创建

        #include<sys/type.h>

        #include<sys/stat.h>

        int mkfifo( const char *pathname, mode_t mode);

参数:

pathname:FIFO的路径名+文件名。

mode:mode_t类型的权限描述符。

返回值: 成功:返回 0 失败:如果文件已经存在,则会出错且返回-1

 fifo_write.c:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
    //创建有名管道(确保两个进程识别相同目录)
    mkfifo("my_fifo",0666);
    //open以写的方式的打开 有名管道(阻塞 到 对方 以读的方式打开)
    int fp=open("my_fifo",O_WRONLY);
    if(fp<0)
    {
        perror("open");
        return 0;
    }
    printf("写端open成功\n");
    while(1)
    {
        //获取键盘输入
        unsigned char buf[128]="";
        printf("请输入需要发送的数据:");
        fgets(buf,sizeof(buf),stdin);
        buf[strlen(buf)-1]=0;
        //发送数据
        write(fp,buf,sizeof(buf));
        //退出循环
        if(strcmp(buf,"Bye")==0)
            break;
    }
    close(fp);
}

 fifo.read.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
    //创建有名管道(确保两个进程识别相同目录)
    mkfifo("my_fifo",0666);
    //open以读的方式的打开 有名管道(阻塞 到 对方 以写的方式打开)
    int fp=open("my_fifo",O_RDONLY);
    if(fp<0)
    {
        perror("open");
        return 0;
    }
    printf("读端open成功\n");
    //循环的读取数据
    while(1)
    {
        //接收数据
        unsigned char buf[128]="";
        read(fp,buf,sizeof(buf));
        printf("收到数据:%s\n", buf);
        //退出循环
        if(strcmp(buf,"Bye")==0)
            break;
    }
    close(fp);
}

 

3、有名管道读写的特点

阻塞方式打开管道:

1、open以只方式打开FIFO时,要阻塞到某个进程为而打开此FIFO

2、open以只方式打开FIFO时,要阻塞到某个进程为而打开此FIFO。

3、open以只读、只写方式打开FIFO时会阻塞,调用read函数从FIFO里读数据时read也会阻塞

4、通信过程中若写进程先退出了,则调用read函数从FIFO里读数据时不阻塞;若写进程又 重新运行,则调用read函数从FIFO里读数据时又恢复阻塞

5、通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会(收到 SIGPIPE信号)退出

6、调用write函数向FIFO里写数据,当缓冲区已满时write也会阻塞

 非阻塞方式打开管道:

1、先以只读方式打开:如果没有进程已经为写而打开一个FIFO, 只读open成功,并且 open不阻塞

2、先以只写方式打开:如果没有进程已经为读而打开一个FIFO,只写open 将出错返回-1

3、read、write读写命名管道中读数据时不阻塞

4、通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会(收到 SIGPIPE信号)退出

注意: open函数以可读可写方式打开FIFO文件时的特点:

        1、open不阻塞

        2、调用read函数从FIFO里读数据时read会阻塞

        3、调用write函数向FIFO里写数据,当缓冲区已满时write也会阻塞

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1848288.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

下载caj viewer查看caj论文

前言 CAJ是“中国学术期刊全文数据库”&#xff08;China Academic Journals&#xff09;的英文缩写&#xff0c;同时也是“中国学术期刊全文数据库”中的一种文件格式。我们从CNKI&#xff08;中国知网&#xff09;下载的资料一般都是这种文件格式。 CAJ不同于PDF等&#xff…

Kimi还能对学术论文进行润色?我来教你!

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 一、引言 在学术界&#xff0c;论文的质量往往决定了研究的可信度和影响力。Kimi作为一款人工智能助手&#xff0c;可以为学术论文的润色提供有效的帮助。本文将详细介绍如何利用Kimi进…

面向对象进阶--抽象(Java 抽象)详解

1.1 抽象类引入 父类中的方法&#xff0c;被它的子类们重写&#xff0c;子类各自的实现都不尽相同。那么父类的方法声明和方法主体&#xff0c;只有声明还有意义&#xff0c;而方法主体则没有存在的意义了(因为子类对象会调用自己重写的方法)。换句话说&#xff0c;父类可能知道…

复盘最近的面试

这个礼拜一直在面试&#xff0c;想着看看能否拿到不错的offer前去实习&#xff0c;从周一到周四&#xff0c;面了将近10家&#xff0c;特整理此份面经&#xff0c;希望对秋招的各位有所帮助 A公司 一面 面试官人很好&#xff0c;我回答的时候不会他会笑笑然后提醒我 自我介绍~…

VMware安装及创建虚拟机

安装完成后&#xff0c;点击创建新的虚拟机 操作完成后就安装成功啦 &#xff0c;下个教程出虚拟机Linux和xshell的连接及可能出现的问题解决方案

Elasticsearch:倒数排序融合 - Reciprocal rank fusion - 8.14

警告&#xff1a;此功能处于技术预览阶段&#xff0c;可能会在未来版本中更改或删除。语法可能会在正式发布之前发生变化。Elastic 将努力修复任何问题&#xff0c;但技术预览中的功能不受官方正式发布功能的支持 SLA 约束。 倒数排序融合 (reciprocal rank fusion - RRF) 是一…

QTday5 2024-06-19

作业要求&#xff1a; 1.思维导图 2.整理代码&#xff1a;TCP服务器 作业1&#xff1a;思维导图 作业2&#xff1a;整理代码 运行代码&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> #include <QList>…

力扣-最长连续序列

文章目录 题目题解解释代码 题目 原题链接&#xff1a;最长连续序列 题解 思路&#xff1a; 定义变量 res 用来记录最长连续序列的长度。对集合中的每个元素进行如下处理&#xff1a; 检查该元素是否是某个连续序列的起点&#xff08;即 num - 1 不在集合中&#xff09;。如…

90 岁老人靠一辆自行车年赚 170 亿,捷安特如何打造山地车极致产品力?

一位富家小开在中年时经商失败&#xff0c;38岁时从零开始创业&#xff0c;最终在自行车整车市场占据了70%的份额&#xff0c;他是怎么做到的&#xff1f; 一家曾为美国自行车品牌代工的台湾工厂&#xff0c;成功从ToB转型为ToC业务&#xff0c;从90%的代工业务转变为全球最大…

迅狐多商户直播商城系统源码:电商领域的创新融合

随着直播技术的兴起和电子商务的蓬勃发展&#xff0c;迅狐多商户直播商城系统源码应运而生&#xff0c;为商家和消费者提供了一个全新的互动购物平台。 多商户直播商城系统源码概述 迅狐多商户直播商城系统源码是一个高度集成的解决方案&#xff0c;它结合了直播的即时性和电…

进入容器修改内容_提交改变后的镜像_镜像保存成tar压缩包离线传输_镜像传输_镜像推送到公共仓库---分布式云原生部署架构搭建009

然后再来看,进入docker内部去看看. 用 docker exec -it imgid /bin/bash 这样就可以进入容器内部 而且关于,镜像的,内部放到什么地方了,都可以找到比如 在hub.docker的地址里面,找到nginx可以看到,对应的 /usr/share/nginx/html 可以看到这个路径. 然后去看看,进入到/usr…

浏览器(Browser):轻量级浏览器,高效浏览新体验

在可的哥桌面&#xff08;Codigger Desktop&#xff09;&#xff0c;我们始终秉持创新精神&#xff0c;致力于提供卓越的用户体验。如今&#xff0c;我们激动地宣布一项全新功能的发布——轻量级浏览器Browser。这款浏览器的推出&#xff0c;正是我们对用户体验追求的再次体现&…

C++:你用过MultiIndex容器吗?

作为C开发者&#xff0c;我们对键值容器非常熟悉&#xff0c;例如std::set、std::map、std::unordered_map等。这些容器以其强大的功能和高效的性能&#xff0c;成为我们处理数据存储和检索任务时的得力助手。但是你用过多键容器&#xff08;MultiIndex&#xff09;吗&#xff…

【大分享06】收、治、用、安“四管齐下”, 做好多业务系统电子文件归档与管理

关注我们 - 数字罗塞塔计划 - 本篇是参加由电子文件管理推进联盟联合数字罗塞塔计划发起的“大分享”活动投稿文章&#xff0c;来自上海泰宇信息技术股份有限公司&#xff0c;作者&#xff1a;金靓。 随着数字政府建设的深入推进以及“互联网政务服务”的快速发展&#xff0c…

TS安装及JS转换

第一步&#xff1a;先安装好node.js&#xff0c;可以在官方下载或我们提供压缩包直接安装好node.js Node.js的官方网站是下载 | Node.js 中文网 下载对应系统的版本。我们提供是64位。安装好后调出dos命名&#xff0c;输入 npm确认下有没有安装好。 第二步&#xff1a;安装cnpm…

初识 GPT-4 和 ChatGPT

文章目录 LLM 概述理解 Transformer 架构及其在 LLM 中的作用解密 GPT 模型的标记化和预测步骤 想象这样⼀个世界&#xff1a;在这个世界里&#xff0c;你可以像和朋友聊天⼀样快速地与计算机交互。那会是怎样的体验&#xff1f;你可以创造出什么样的应用程序&#xff1f;这正是…

【Linux进程】手把手教你如何调整----进程优先级(什么是优先级?为什么要有优先级?)

目录 一、前言 二、优先级的基本概念 &#x1f95d; 什么是优先级&#xff1f; &#x1f34d; 为什么要有优先级&#xff1f; 三、如何查看并修改 --- 进程优先级 &#x1f347; PRI and NI &#x1f525;PRI&#x1f525; &#x1f525;NI&#x1f525; &#x1f3…

关键属性描述ASYNC_REG

关键属性描述 属性信息 本章提供有关XilinxVivadoDesign Suite属性的信息。条目 每个属性包含以下信息&#xff08;如适用&#xff09;&#xff1a; •物业说明&#xff0c;包括其主要用途。 •支持该特性的Xilinx FPGA体系结构&#xff0c;包括UltraScale™ 架构设备&#xff…

【fiddler】fiddler抓取websocket

1.先了解websocket流 下载4.5版本以上的fiddler 如图所示&#xff1a;在rules--customize rules 里面插入以下代码&#xff1a; static function OnWebSocketMessage(oMsg: WebSocketMessage) { // Log Message to the LOG tab FiddlerApplication.Log.LogString(oMsg.ToStr…

docker最详细基础教程:如何在Win11中使用docker desktop

目录 前言 界面说明 设置界面翻译图一些简单说明 主要功能界面介绍 关于切换docker镜像源 如何拉取镜像 搜索镜像 创建容器 docker run命令的OPTIONS详细介绍 设置容器名词 以后台模式运行容器 端口映射 设置挂载卷 设置环境变量 容器退出后自动删除容器 容器…