进程间通信-----管道
来源:互联网 发布:蚂蚁活多久 知乎 编辑:程序博客网 时间:2024/06/05 18:32
1、概念:一个进程将它的数据发送给另一个进程
2、管道通信
2.1、概念:
管道是单向的、先进先出的,它把一个进程的输出和另一个进程的输入连接在一起。一个进程(写进程)在管道尾部写入数据,另一个进程(读进程)从管道的头部读出数据。
2.2:简单的程序间的数据传输 popen
两个程序之间传递数据的一种简单方法是使用popen和pclose。
格式:FILE *popen(const char *command, const char *type);
popen函数允许一个程序将另一个程序作为新进程来启动,并可以传递数据给它或者通过它接收数据。command字符串是要运行的程序名和相应的参数。type必须是”r”或”w”。
如果type是”r”,被调程序的输出就可以被调用程序使用,调用程序利用popen函数返回的FILE *文件流指针,可以读取被调程序的输出;如果type是”w”,调用程序就可以向被调程序发送数据,而被调程序可以在自己的标准输入上读取这些数据。
pclose格式:int pclose(FILE *stream);
pclose函数只在popen启动的进程结束后才返回。如果调用pclose时它仍在运行,pclose将等待该进程的结束。
看代码:利用模型ps - ef |grep a.out(ps - ef的结果通过管道传给grep a.out)
#include <stdio.h>#define SIZE 1024*100int main(){ FILE *fp = popen("ps -ef", "r");//读取调用程序ps-ef的运行结果到文件指针fp,在读到缓冲区; if (fp == NULL) { perror ("popen"); return -1; } char buf[SIZE] = {0}; int ret = fread(buf, sizeof(char), SIZE-1, fp); // printf ("读到的数据:\n %s\n", buf); FILE *fp2 = popen("grep a.out", "w"); if (fp2 == NULL) { perror ("popen"); return -1; } fwrite (buf, sizeof(char), ret, fp2);//缓冲区的数据写到程序grep a.out中;给fp2传数据; printf ("写入完成\n"); pclose (fp); pclose (fp2); return 0;}
2.3、无名管道(用于父子间数据通信)
(1)无名管道由pipe()函数创建:
int pipe(int filedis[2])
当创建这个函数的时候会创建两个文件描述符一个fd[0]代表读,一个fd[1]代表写,存放在数组里边;
(2)代码例子
#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <string.h>#define SIZE 1024// 子进程通过管道从父进程接收数据void child_do(int *fd){ // 将管道的写端关闭 close (fd[1]); char buf [SIZE]; while (1) { // 从父进程读取数据 int ret = read (fd[0], buf, SIZE-1); if (ret == -1) { perror ("read"); break; } buf[ret] = '\0'; printf ("子进程读到 %d 字节数据: %s\n", ret, buf); } // 关闭读端 close (fd[0]);}// 父进程通过管道向子进程发送数据void father_do(int *fd){ // 将管道读端关闭 close (fd[0]); char buf[SIZE]; while (1) { fgets (buf, SIZE, stdin); // 向子进程发送数据 int ret = write (fd[1], buf, strlen(buf)); printf ("父进程发送了 %d 字节数据\n", ret); } // 关闭写端 close (fd[1]);}int main(){ int fd[2]; // 创建管道 int ret = pipe(fd); if (ret == -1) { perror ("pipe"); return -1; } // 创建子进程 pid_t pid = fork(); switch (pid) { case -1: perror ("fork"); break; case 0: // 子进程 child_do(fd); break; default: father_do(fd); break; } return 0;}
注意点:
1.先创建管道再fork()创建子进程,因为创建的子进程会复制一份父进程的代码到自己的进程,继承的还是那一个管道,所以这样父子进程公用一个管道,要是先fork()再创建管道,这就是两个进程创建了两个管道了!
2.虽然是共用同一个管道,但是父子进程他们分别都会有自己的读端和写端,现在有两个读端,两个写端指向这个管道,所以我们在操作的时候需要关掉一个读和写!
3.当读端都被关闭了之后,要是继续往管道写数据的话,会发生错误,进程会收到内核传来的错误信号;此进程结束!(如果管道所有的读端都被关闭,继续写数据系统默认的操作是使程序退出)
2.4、有名管道
(1)创建
int mkfifo(const char *pathname, mode_t mode)
当创建这个函数的时候会创建两个文件描述符一个fd[0]代表读,一个fd[1]代表写,存放在数组里边;
参数解释:
pathname: FIFO文件名
mode:属性(权限和设置文件权限一样可读or可写or可执行);
注意:
一旦创建了一个FIFO,就可用open打开它,一般的文件访问函数(close、read、write等)都可用于FIFO。
创建代码:
#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>int main(){ int ret = mkfifo("/home/mkfifo", 0777); if (ret == -1) { perror ("mkfifo"); return -1; } return 0;}
(2)例子
上边已经创建好了那个命名管道,现在我们就用两个程序打开那个管道,程序1在一段给他写数据,程序2 在另一端给他读数据;
程序1(写数据):
<string.h>#include <fcntl.h>#define SIZE 1024int main(){ //打开了管道,给一个描述符; int fd = open("/home/mkfifo", O_WRONLY); if (fd== -1) { perror ("mkfifo"); return -1; } char buf[SIZE]; while (1) { fgets (buf, SIZE, stdin); //缓冲区写进管道; write (fd, buf, strlen(buf)); } return 0;}
程序2(读数据):
#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <string.h>#include <fcntl.h>#define SIZE 1024int main(){ int fd = open("/home/mkfifo", O_RDWR); if (fd == -1) { perror ("mkfifo"); return -1; } char buf[SIZE]; while (1) { //在管道一段读取数据,读到缓冲区,打印输出到屏幕上; int ret = read (fd, buf, SIZE); buf[ret] = '\0'; printf ("读到 %d 字节: %s\n", ret, buf); } return 0;}
注意点:
当打开命名管道时,非阻塞标识(O_NONBLOCK)将对以后的读写产生影响,也就是没有使用O_NONBLOCK:访问要求无法满足时进程将阻塞。
要是使用了O_NONBLOCK之后遇到要求无法满足的情况的时候会返回error直接返回;
- 进程间管道通信
- 进程间通信: 管道
- 进程间通信--管道
- 进程间通信----管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信----管道
- 进程间通信----管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信-管道
- 进程间管道通信
- 进程间管道通信
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信-管道
- Python中re的用法示例
- Node创建服务器对象
- byte类型运算细节
- UVA11971Polygon
- 菜鸟新手的知识汲取(5)JAVA基础之构造器
- 进程间通信-----管道
- 科技发展推动智慧环卫,有望破解行业难题?
- js的练习题(1)
- NYOJ138
- 【Python3.6爬虫学习记录】(五)Cookie的使用以及简单的爬取知乎
- 设置图片圆角边框
- vue2.x---在vue2.x中,父组件怎么响应式向子组件传值,子组件怎么通过prop修改父组件数据?
- java之简单的回文算法
- hdu 5256 LIS变形