详解linux进程间通信-管道 popen函数 dup2函数
前言:进程之间交换信息的唯一方法是经由f o r k或e x e c传送打开文件,或通过文件系统。本章将说明进程之间相互通信的其他技术—I P C(InterProcess Communication)。今天将介绍半双工的管道。
一、匿名管道
1、匿名管道介绍:
管道有两种限制;
(1) 它们是半双工的。数据只能在一个方向上流动。
(2)它们只能在具有公共祖先的进程之间使用。通常,一个管道由一个进程创建,然后该进程调用f o r k,此后父、子进程之间就可应用该管道。
管道是由调用p i p e函数而创建的:
#include <unistd.h>
int pipe(intf i l e d e s [ 2 ]) ;
返回:若成功则为0,若出错则为 - 1
经由参数f i l e d e s返回两个文件描述符: f i l e d e s [ 0 ]为读而打开, f i l e d e s [ 1 ]为写而打开。 f i l e d e s [ 1 ]
的输出是f i l e d e s [ 0 ]的输入。
程序1- 1创建了一个从父进程到子进程的管道,并且父进程经由该管道向子进程传送数据。
- #include "my.h"
- int main()
- {
- int pfd[],ret;
- ret = pipe(pfd);//创建管道
- if(ret<)
- {
- perror("pipe error!");
- exit(-);
- }
- pid_t pid = fork();
- if(pid<)
- {
- perror("fork error!");
- exit(-);
- }
- else if(pid>)//父进程
- {
- close(pfd[]);
- int num;
- puts("please input your num:");
- scanf("%d",&num);
- write(pfd[],&num,sizeof(num));
- //wait(NULL);
- }
- else //子进程
- {
- close(pfd[]);
- int num;
- read(pfd[],&num,sizeof(num));
- printf("num:%d\n",num);
- }
- return ;
- }
注:头文件my.h见这篇博客:http://www.cnblogs.com/liudw-0215/p/8946879.html
运行示例,如下图:
接下来介绍几个跟管道有关的函数。
2、dup和d u p 2函数
下面两个函数都可用来复制一个现存的文件描述符:
#include <unistd.h>
int dup(intf i l e d es) ;
int dup2(int f i l e d e s, int f i l e d e s 2) ;
两函数的返回:若成功为新的文件描述符,若出错为- 1
由d u p返回的新文件描述符一定是当前可用文件描述符中的最小数值。用 d u p 2则可以用f i l e d e s 2
参数指定新描述符的数值。如果 f i l e d e s 2已经打开,则先将其关闭。如若f i l e d e s等于f i l e d e s 2,则
d u p 2返回f i l e d e s 2,而不关闭它。
优化程序1-1,程序1-2如下:
- #include "my.h"
- int main()
- {
- int pfd[],ret;
- ret = pipe(pfd);
- if(ret<)
- {
- perror("pipe error!");
- exit(-);
- }
- pid_t pid = fork();
- if(pid<)
- {
- perror("fork error!");
- exit(-);
- }
- else if(pid>)
- {
- close(pfd[]);
- int num;
- puts("please input your num:");
- scanf("%d",&num);
- write(pfd[],&num,sizeof(num));
- wait(NULL);
- }
- else
- {
- close(pfd[]);
- dup2(pfd[],STDIN_FILENO);//pfd[0]复制到标准输入
- int num;
- read(STDIN_FILENO,&num,sizeof(num));
- printf("num:%d\n",num);
- }
- return ;
- }
- 3、popen和p c l o s e函数
- 因为常见的操作是创建一个连接到另一个进程的管道,然后读其输出或向其发送输入,所
以标准I / O库为实现这些操作提供了两个函数 p o p e n和p c l o s e。这两个函数实现的操作是:创建
一个管道, f o r k一个子进程,关闭管道的不使用端, e x e c一个s h e l l以执行命令,等待命令终止。
#include <stdio.h>
FILE *popen(const char * c m d s t r i n g, const char * t y p e) ;
返回:若成功则为文件指针,若出错则为 N U L L
int pclose(FILE * f p) ;
返回: c m d s t r i n g的终止状态,若出错则为 - 1
函数popen 先执行f o r k,然后调用e x e c以执行c m d s t r i n g,并且返回一个标准 I / O文件指针。
如果t y p e是"r",则文件指针连接到c m d s t r i n g的标准输出。
如果t y p e 是"w",则文件指针连接到c m d s t r i n g 的标准输入。
程序1-3将用popen函数实现下图功能:
- #include "my.h"
- int main()
- {
- int c;
- while((c = getchar()) != EOF)
- {
- if(isupper(c)) //是否有大写
- c = tolower(c); //转为小写
- if(putchar(c) == EOF)
- puts("put error!");
- if(c == '\n')
- fflush(stdout); //刷新标准输出
- }
- exit();
- }
- ---isupper.c---
- #include "my.h"
- #define MAXLINE 4096
- int main()
- {
- char line[MAXLINE];
- FILE *fpin;
- if((fpin = popen("./upper","r")) == NULL)
- perror("popen error!");
- for(;;){
- fputs("prompt > ",stdout);
- fflush(stdout);
- if(fgets(line,MAXLINE,fpin) == NULL)
- break;
- if(fputs(line,stdout) == EOF)
- perror("puts error!");
- }
- if(pclose(fpin) == -)
- perror("pclose error!");
- putchar('\n');
- return ;
- }
- ---popen.c---
运行演示如下图:
二、有名管道(命名管道)
1、简介
命名管道有时被称为FIFO。管道只能由相关进程使用,它们共同的祖先进程创建了管道。
但是,通过F I F O,不相关的进程也能交换数据。
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char * p a t h n a m e, mode_tm o d e) ;
返回:若成功则为0,若出错则为 - 1
m k f i f o函数中m o de参数的规格说明与o p e n函数中的m o d e相同。
一旦已经用 m k f i f o创建了一个 F I F O,就可用 o p e n打开它。确实,一般的文件 I / O函数
(c l o s e、 r e a d、 w r i t e、 u n l i n k等)都可用于F I F O。
程序2-1演示有名管道通信,一个写端、一个读端:
- #include "my.h"
- typedef struct{
- char name[];
- int age;
- double height;
- }Person;
- int main()
- {
- mkfifo("pipe",);//创建管道 名字为pipe
- int fd = open("pipe",O_WRONLY);
- if(fd < )
- {
- perror("open error!");
- exit(-);
- }
- Person p;
- puts("please input your name,age,height:");
- scanf("%s%d%lf",p.name,&p.age,&p.height);
- write(fd,&p,sizeof(p));
- close(fd);
- return ;
- }
---fwrite.c---
- #include "my.h"
- typedef struct{
- char name[];
- int age;
- double height;
- }Person;
- int main()
- {
- int fd = open("pipe",O_RDONLY);
- if(fd < )
- {
- perror("open error!");
- exit(-);
- }
- Person p;
- read(fd,&p,sizeof(p));
- printf("name:%-5sage:%-5dheight:%-5lf\n ",p.name,p.age,p.height);
- close(fd);
unlink("pipe");//删除管道文件- return ;
- }
--- fread.c ---
运行演示:先编译fwrite.c生成w可执行用户,./w执行,再编译fread.c然后执行,写端输入数据,读端输出数据:
总结:主要介绍了进程间通信的管道,主要分为匿名管道和有名管道,还介绍了popen等函数
详解linux进程间通信-管道 popen函数 dup2函数的更多相关文章
- 详解linux进程间通信-信号
前言:之前说看<C++ Primer >暂时搁浅一下,迷上公司大神写的代码,想要明白,主要是socket.进程间通信! 知道进程间通信:信号.信号量.管道.消息队列.共享内存(共享存储), ...
- 详解linux进程间通信-消息队列
前言:前面讨论了信号.管道的进程间通信方式,接下来将讨论消息队列. 一.系统V IPC 三种系统V IPC:消息队列.信号量以及共享内存(共享存储器)之间有很多相似之处. 每个内核中的 I P C结构 ...
- linux dmesg命令参数及用法详解(linux显示开机信息命令)
linux dmesg命令参数及用法详解(linux显示开机信息命令) http://blog.csdn.net/zhongyhc/article/details/8909905 功能说明:显示开机信 ...
- Linux进程上下文切换过程context_switch详解--Linux进程的管理与调度(二十一)
1 前景回顾 1.1 Linux的调度器组成 2个调度器 可以用两种方法来激活调度 一种是直接的, 比如进程打算睡眠或出于其他原因放弃CPU 另一种是通过周期性的机制, 以固定的频率运行, 不时的检测 ...
- linux下sort命令使用详解---linux将文本文件内容加以排序命令
转载自:http://www.cnblogs.com/hitwtx/archive/2011/12/03/2274592.html linux下sort命令使用详解---linux将文本文件内容加以排 ...
- Linux下ps命令详解 Linux下ps命令的详细使用方法
http://www.jb51.net/LINUXjishu/56578.html Linux下的ps命令比较常用 Linux下ps命令详解Linux上进程有5种状态:1. 运行(正在运行或在运行队列 ...
- 详解Linux交互式shell脚本中创建对话框实例教程_linux服务器
本教程我们通过实现来讲讲Linux交互式shell脚本中创建各种各样对话框,对话框在Linux中可以友好的提示操作者,感兴趣的朋友可以参考学习一下. 当你在终端环境下安装新的软件时,你可以经常看到信息 ...
- linux useradd(adduser)命令参数及用法详解(linux创建新用户命令)
linux useradd(adduser)命令参数及用法详解(linux创建新用户命令) useradd可用来建立用户帐号.帐号建好之后,再用passwd设定帐号的密码.而可用userdel删除帐号 ...
- 详解linux运维工程师入门级必备技能
详解linux运维工程师入门级必备技能 | 浏览:659 | 更新:2013-12-24 23:23 | 标签:linux it自动化运维就是要很方便的运用各种工具进行管理维护,有效的实施服务器保护 ...
随机推荐
- SpringBoot的HelloWorld 应用及解释
参考链接: Spring Data JPA - Reference Documentation Spring Data JPA--参考文档 中文版 纯洁的微笑:http://www.ityouknow ...
- js基本包装类型和引用类型
回顾 1.什么是基本类型? 共5个.boolean,string,number,null,undefined. 2.什么是引用类型? 引用类型的值是对象,保存在堆内存中: 引用类型的变量实际上是一个指 ...
- python继承——封装
python继承--封装 1 为什么要封装 封装数据的主要原因是:保护隐私 封装方法的主要原因是:隔离复杂度 2 封装分为两个层面 第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空 ...
- 已操作文件的方式,新建一个用户alex
- I/O和管道
一:I/O设备 I/O(Input/Output),即输入/输出,通常指数据在内部存储器和外部存储器或其他周边设备之间的输入和输出. 标准输入(STDIN):0 默认接受来自键盘的输入 标准输出(ST ...
- 编码注释coding: utf-8
# -*- coding: utf-8 -*- PY文件当中是不支持中文的,即使你输入的注释是中文也不行,为了解决这个问题,就需要把文件编码类型改为UTF-8的类型,输入这个代码就可以让PY源文件里面 ...
- JavaScript sort() 方法
定义和用法 sort() 方法用于对数组的元素进行排序. 语法 arrayObject.sort(sortby) 参数 描述 sortby 可选.规定排序顺序.必须是函数. 返回值 对数组的引用.请注 ...
- 基于 MySQL 的数据库实践(基本查询)
首先根据准备工作中的操作导入大学模式,打开数据库连接后进入到 MySQL 的交互界面,再使用命令 use db-book; 切换到 db-book 数据库. 单关系查询 SQL 查询的基本结构由三个子 ...
- 百度tn劫持解决办法
最近用右键进行百度搜索的时候总是会跳转到 tn=99135173这类的小尾巴,使得搜索失败,十分恶心,这种广告劫持的手段十分高明隐蔽,很难发觉.开始以为是dns劫持或者是电脑中毒了,更换了几个dns, ...
- 深入理解Redux
前面的话 Redux是Flux思想的另一种实现方式.Flux是和React同时面世的.React用来替代jQuery,Flux用来替换Backbone.js等MVC框架.在MVC的世界里,React相 ...