Linux编程基础 5.1:管道

1 简介

Linux进程通信机制:

  • 管道
  • 信号量
  • 消息队列
  • 共享内存
  • socket通信

2 管道

在这里插入图片描述
管道其实质是由内核管理的一个缓冲区
形象地认为管道的两端连接着两个进程:

  • 一个进程进行信息输出,将数据写入管道;
  • 另一个进程进行信息输入,从管道中读取信息。

管道分为:

  • 匿名管道:只能用于有亲缘关系的进程间通信,进程退出后管道会被销毁。
  • 命名管道:命名管道与进程的联系较弱,相当于一个读写内存的接口,进程退出后,命名管道依然存在。

2.1 匿名管道

匿名管道的使用流程如下:
①在进程中创建匿名管道,pipe函数;
②关闭进程中不使用的管道端口,close函数;
③在待通信的进程中分别对管道的读、写端口进行操作,read/write函数;
④关闭管道,close函数。

2.1.1 pipe函数

#include <unistd.h>
int pipe(int pipefd[2]);

功能:创建匿名管道

参数说明

  • pipefd:传入参数,一个文件描述符数组;Linux将管道抽象为一个特殊文件。

返回值说明

  • 成功:返回0.
  • 不成功:返回-1。

【案例1】使用pipe()实现父子进程间通信,父进程作为读端,子进程作为写端。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){int tempFd[2];//定义文件描述符数组int tempRet=pipe(tempFd);//创建管道if(tempRet == -1){   perror("pipe");exit(1);}   pid_t tempPid=fork();if(tempPid > 0){//父进程—读close(tempFd[1]);//关闭写端char tempBuf[64]={0};tempRet = read(tempFd[0], tempBuf, sizeof(tempBuf));//读数据close(tempFd[0]);write(STDOUT_FILENO, tempBuf, tempRet);//将读到的数据写到标准输出wait(NULL);} else if(tempPid == 0){//子进程—写close(tempFd[0]);//关闭读端char *tempStr="hello,pipe\n";write(tempFd[1], tempStr, strlen(tempStr)+1);//写数据close(tempFd[1]);}//of ifreturn 0;
}//of main

分析如下:
pipe()创建管道后读端的文件描述符为fd[0],写端的文件描述符为fd[1];
调用fork后父子进程共享文件描述符,文件描述符与管道的关系如图所示:
在这里插入图片描述

父进程进行读操作,子进程进行写操作;使用close()函数关闭父进程的写端与子进程的读端。
在这里插入图片描述
在这里插入图片描述

2.1.2 dup2函数

【案例2】使用管道实现兄弟进程间通信,兄弟进程实现命令“ls | wc –l”的功能。

  • 在实现本案例时会用到重定向函数dup2:
#include <unistd.h>
int dup2(int oldfd, int newfd);
  • 其功能是将参数oldfd的文件描述符复制给newfd
  • 若函数调用成功则返回newfd
  • 否则返回-1,并设置errno。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){int tempFd[2];int tempRet = pipe(tempFd);if(tempRet == -1){perror("pipe err");exit(1);}//of if   int i;pid_t tempPid, tempWpid;for(i=0; i<2; i++){//2个子if((tempPid = fork()) == 0){break;}//of if}//of ifif(2 == i){//父进程,回收子进程close(tempFd[0]); //关闭读close(tempFd[1]); //关闭写tempWpid = wait(NULL);printf("wait child 1 success,pid=%d\n", tempWpid );tempPid = wait(NULL);printf("wait child 2 success,pid=%d\n", tempPid);} else if(0 == i){//子进程1—写close(tempFd[0]);dup2(tempFd[1], STDOUT_FILENO);//定向到标准输出execlp("ls", "ls", NULL);} else if(1 == i){//子进程2—读close(tempFd[1]);dup2(tempFd[0], STDIN_FILENO);execlp("wc", "wc", "-l", NULL);}//of ifreturn 0;
}//of main

注意:

int execlp(const char *file, const char *arg, ...);

execlp是一个可变参数函数。它需要2个const char *。其余的参数(如果有的话)为转移到运行程序的附加参数,也是char * ,最后一个参数必须是NULL指针。
所以,文件参数是要执行的可执行文件的路径名。 arg是我们想在可执行文件中显示为argv [0]的字符串。按照惯例,argv [0]只是可执行文件的文件名,通常它被设置为与文件相同。

兄弟进程间通信,进程文件描述符与管道的关系如图所示:
在这里插入图片描述:
实线所示的箭头为编程中需要保留的文件描述符

2.1.3 popen/pclose函数

Linux标准I/O库两个函数popen()和pclose(),可完成管道通信的流程。

#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);

功能
popen函数的功能是:

  • 调用pipe()函数创建管道;
  • 调用fork()函数创建子进程;
  • 之后在子进程中通过execve()函数调用shell命令执行相应功能。

pclose函数的功能:

  • 关闭popen()打开的I/O流;
  • 通过调用wait()函数等待子进程命令执行结束;
  • 返回shell的终止状态,防止产生僵尸进程。

参数说明
popen函数的参数:

  • command:命令;
  • type:指定命令类型(输入w/输出r);

pclose函数的参数:

  • stream:I/O流。

返回值说明
popen函数的返回值:

  • 成功:管道文件的描述符;
  • 不成功:返回-1。

pclose函数的返回值:

  • 成功:0;
  • 不成功:-1。

【案例3】使用popen与pclose函数实现管道通信。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){FILE *tempRfp,*tempWfp;char temBuf[100];tempRfp = popen("ls","r");		//读取命令执行结果tempWfp = popen("wc -l","w");	//将管道中的数据传递给进程while(fgets(temBuf, sizeof(temBuf), tempRfp)!=NULL){fputs(temBuf, tempWfp);}//of while   pclose(tempRfp);pclose(tempWfp);return 0;
}//of main

2.2 命名管道

#include <sys/type.h>
#include <sys/stat.h>int mkfifo(const char *pathname, mode_t mode);

功能:创建命名管道(FIFO文件),命名管道与系统中的一个路径名关联,以文件的形式存在于文件系统中,通过FIFO的路径名访问FIFO文件,实现进程间通信。

参数说明

  • pathname:管道文件的路径名,通过FIFO路径名访问FIFO文件;
  • mode:指定FIFO的权限;

返回值说明

  • 成功:0;
  • 不成功:-1,并设置errno。

【案例4】使用FIFO实现没有亲缘关系进程间的通信。没有亲缘关系的进程间通信,需要两段程序来实现:

  • fifo_write.c实现FIFO的写操作;
  • fifo_read.c实现FIFO的读操作。
fifo_write.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int paraArgc,char *paraArgv[]){if(paraArgc < 2){							//判断是否传入文件名printf("./a.out fifoname\n");exit(1);}//of ifint tempRet = access(paraArgv[1], F_OK);	//判断fifo文件是否存在if(tempRet == -1){							//若fifo不存在就创建fifo int tempFIFO = mkfifo(paraArgv[1], 0664);if(tempFIFO == -1){						//判断文件是否创建成功perror("mkfifo");exit(1);} else{printf("fifo creat success!\n");}//of if}//of ifint tempFd = open(paraArgv[1], O_WRONLY);		//读写方式打开while(1){									//循环写入数据char *tempStrp="hello,world!";write(tempFd, tempStrp, strlen(tempStrp)+1);sleep(1);}//of whileclose(tempFd);return 0;
}//of mainfifo_read.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int paraArgc,char *paraArgv[]){if(paraArgc < 2){						//判断是否传入文件名printf("./a.out fifoname\n");exit(1);}//of ifint tempRet = access(paraArgv[1], F_OK);	//判断fifo文件是否存在if(tempRet == -1){						//若fifo不存在就创建fifo int tempFIFO = mkfifo(paraArgv[1], 0664);if(tempFIFO == -1){					//判断文件是否创建成功perror("mkfifo");exit(1);} else{printf("fifo creat success!\n");}//of if}//of ifint tempFd = open(paraArgv[1], O_RDONLY);	//只读方式打开if(tempFd == -1){perror("open");exit(1);}//of ifwhile(1){								//不断读取fifo中的数据并打印char temBuf[1024]={0};read(tempFd, temBuf, sizeof(temBuf));printf("buf=%s\n", temBuf);}//of whileclose(tempFd);							//关闭文件return 0;
}//of main

FIFO文件和普通文件的区别:

  • FIFO文件是对内存进行操作;
  • 普通文件是存储在硬盘;
  • 对内存的的读取会比硬盘的读写要快很多;
  • 两个进程通过普通文件通信当然也是可以的。

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

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

相关文章

python pd Series 添加行_Python数据分析与挖掘的常用工具

Python语言&#xff1a;简要概括一下Python语言在数据分析、挖掘场景中常用特性&#xff1a;列表(可以被修改)&#xff0c;元组(不可以被修改)字典(结构)集合(同数学概念上的集合)函数式编程(主要由lambda()、map()、reduce()、filter()构成)Python数据分析常用库&#xff1a;P…

华为荣耀20和x10比较_荣耀X10和华为畅享20plus,到底哪个更值得入手?

今天&#xff0c;我接到了联通客服的电话&#xff0c;说我是老用户&#xff0c;直接给我升级成了5G套餐&#xff0c;资费没有太多的变化&#xff0c;比起以前每月月租只多了一块钱&#xff0c;也就是从原来的48元一个月变成了49元一个月&#xff0c;就加了一元钱就变成了5G套餐…

Linux编程基础 5.2:消息队列

3 消息队列 消息队列的本质是一个存放消息的链表&#xff0c;该链表由内核来维护。一个消息队列由一个标识符&#xff08;即队列key&#xff09;来标识。消息队列的通信机制传递的数据具有某种结构&#xff0c;而不是简单的字节流&#xff1b;向消息队列中写数据&#xff0c;实…

python tab和空格混用_Python编程常见十大错误,看完你自己都笑了!

关注并置顶【柠檬班】的小哥哥小姐姐胸有成“猪”使用python会出现各种各样的错误&#xff0c;以下是Python常见的错误以及解决方法。01 ValueErrorValueError: ‘Conv2d_1a_33’ is not a valid scope name其实这就是命名错误的问题&#xff0c;如果仔细看“”是我在中文下打的…

Linux编程基础 5.3:信号量

4 信号量 信号量是专门用来解决进程同步与互斥问题的一种通信机制&#xff0c;它与信号无关&#xff1b;不同于管道、FIFO以及消息队列&#xff0c;一般不用来传输数据&#xff1b;信号量包括&#xff1a;表示资源数量的非负整型变量、修改信号量的原子操作P和V、该信号量下等…

谷歌浏览器外贸版_针对谷歌SEO,你有哪些值得推荐的工具、插件、网站、app,或者技巧分享?...

接触并了解谷歌SEO也有3年了&#xff0c;这3年来&#xff0c;一直钻研这块技术和工具&#xff0c;今天刚好看到这个问题&#xff0c;就分享下。目前谷歌SEO主要分3大块&#xff0c;站内SEO(On page seo&#xff0c;做好站内优化)&#xff0c;站外SEO(off page seo 主要是外链)&…

hadoopsdk使用_hadoop部署使用问题及解决

在cygwin环境中填写路径信息时务必注意将“\”替换为“/”。hadoop文件夹名称不能包含“-”&#xff0c;比如“hadoop-2.4.0”会出错。在cygwin环境中尽管“C:\abc”和“/cygdrive/c/abc”都可以被正确识别&#xff0c;但某些软件会将前者识别为相对路径&#xff0c;从而出现错…

Linux编程基础 5.4:共享内存

5 共享内存 共享内存允许两个或多个进程访问给定的同一块存储区域。它是效率最高的一种进程通信方式&#xff0c;节省了不同进程间多次读写的时间&#xff1b;在写进程的操作尚未完成时&#xff0c;不应有进程从共享内存中读取数据。共享内存自身不限制对共享内存的读写次序&a…

升级浏览器_微软IE11浏览器 最后的升级机会

微软IE10浏览器将很快退出支持&#xff0c;许多Windows用户将没有任何安全或非安全更新&#xff0c;免费或付费辅助支持选项或在线技术内容等。幸运的是&#xff0c;微软正在为Windows用户提供升级到IE11的最后机会&#xff0c;目前IE11仅次于Firefox浏览器&#xff0c;这是互联…

jq如何获取选中option的值_【分享】如何获取变量token的值

一.什么是token客户端使用用户名跟密码请求登录服务端收到请求&#xff0c;去验证用户名与密码验证成功后&#xff0c;服务端会签发一个 Token&#xff0c;再把这个 Token 发送给客户端客户端收到 Token 以后可以把它存储起来&#xff0c;比如放在 Cookie 里或者 LocalStorage …

Linux编程基础 6.1:线程操作

1 线程操作 创建线程 挂起线程 终止线程 其它操作 1.1 创建线程 #include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); 功能&#xff1a;创建线程&#xff1b;线程调用pthread_crea…

灯效控制器和rgb控制器_更具个性的RGB风扇,机箱里的魔术师,九州风神MF120GT开箱...

写在前面不知道在2020年还有多少人会自己装机&#xff0c;相信喜欢个性的DIY玩家还是会陆陆续续跳进这个不小的坑。装机的乐趣在哪里&#xff0c;除了几大硬件&#xff0c;显然个性的灯效才是装机的灵魂。在光污染的道路上&#xff0c;普通的光环&#xff0c;光面等风扇&#x…

华为交换机ssh思科交换机_华为交换机SSH(stelnet)配置实例教程

Stelnet(安全telnet)登陆也成为shh(sercure shell,安全外壳)登陆-----------必要配置---------------1、先根据加密算法生成秘钥对,用于传输数据时加密保护&#xff0c;保存在交换机中但不保存在配置文件中[Huawei]rsa local-key-pair create或[Huawei]dsa local-key-pair crea…

Linux编程基础 6.2:线程同步

2 线程同步 线程同步中的“同步”与生活中大家认知的“同步”略有不同&#xff0c;“同”不指同时&#xff0c;其主旨在于协同步调&#xff0c;按预定的先后次序执行线程&#xff1b;之所以需要实现线程同步&#xff0c;是因为若不对线程的执行次序加以控制&#xff0c;可能会…

电脑开两个微信_电脑怎么登录两个微信

1/4下载并安装微信电脑客户端&#xff0c;保证这台电脑没有登陆微信2/4就像正常打开微信一样&#xff0c;不过不是双击&#xff0c;而是快速连点四次3/4我们可以看到有两个微信登陆界面4/4用两个不同的账号进行扫码登陆即可

idea 查询项目代码行数_idea统计代码行数Statistic的步骤详解

idea统计代码行数Statistic的步骤详解idea统计代码行数可以用到插件&#xff1a;Statistic。步骤&#xff1a;File→Settings进入Plugins点击Marketplace搜索Statistic 安装蓝框标出的插件重启idea后就可以看到效果了(图是拿的别人的&#xff0c;基本就是这效果)如果没有下…

Linux编程基础 7.1:套接字通信流程及编程接口

1 socket通信流程 2 socket编程接口 Linux系统中常用的socket网络编程接口有&#xff1a; socket()bind()listen()accept()connect()send()recv()close()其中connect()与send()为客户端专用接口&#xff1b;bind()、listen()、accept()及recv()为服务器端专用接口&#xff1b…

cad2016中选择全图字体怎么操作_cad教程分享CAD中如何删除顽固图层?

Autocad教程公众号&#xff0c;专注于cad教程、cad教程视频的分享&#xff0c;欢迎关注&#xff0c;下载你所需的教程资源&#xff01;如你还未关注&#xff0c;请点击文章标题下方蓝色字体的"Autocad教程"进行关注。cad教程分享-CAD中如何删除顽固图层&#xff1f;方…

python开启多个端口服务_python bottle使用多个端口(多个进程)提高并发

我的程序是用python结合bottle框架写的&#xff0c;但bottle自带wsgi原本只是单进程单线程运行模式(Bottle 默认运行在内置的 wsgiref 服务器上面。这个单线程的 HTTP 服务器在开发的时候特别有用&#xff0c;但其性能低下&#xff0c;在服务器负载不断增加的时候也许会是性能瓶…

Linux编程基础 7.2:服务器和客户端编程案例

1 网络字节序 大端模式&#xff1a;若将数据的高字节保存在内存的低地址&#xff0c;将数据的低字节保存在内存的高地址&#xff1b; 小端模式&#xff1a;若将数据的高字节保存在内存的高地址&#xff0c;将数据的低字节保存在内存的低地址。 网络数据流&#xff1a;大端模式…