linux程序设计——pipe调用在两进程之间通信(第十三章)

原创 2015年07月10日 18:51:46

13.4    pipe调用

在看过高级的popen函数之后,再来看看底层的pipe函数.通过这个函数在两个程序之间传递数据不需要启动一个shell来解释请求的命令.它同时提供了对读写数据的更多控制.
pipe函数的原型如下所示:
#include <unistd.h>
int pipe(int file_descriptor[2]);
参数:是一个由两个整数类型的文件描述符组成的数组.
返回值:该函数在数组中填上两个新的文件描述符,如果成功则返回0,如果失败则返回-1并设置errno来表明失败的原因.
错误描述:
EMFILE:进程使用的文件描述符过多
ENFILE:系统的文件表已满
EFAULT:文件描述符无效
调用pipe之后,两个文件描述符以一种特殊的方式连接起来.写到file_descrpter[1]的所有数据都可以从file_descripter[0]读回.数据基于先进先出的原则进行处理,这意味着如果把字节1,2,3写到file_descripter[1],从file_descripter[0]读取到的数据也会是1,2,3.
特别要注意,这里使用的是文件描述符而不是文件流,所以必须用底层的read和write调用来访问数据,而不是文件流库函数fread和fwrite.
编写程序pipe1.c,它用pipe函数创建一个管道.
<pre name="code" class="cpp">/*************************************************************************
 > File Name:    pipe1.c
 > Description:  pipe1.c程序用pipe函数创建一个管道
 > Author:       Liubingbing
 > Created Time: 2015年07月10日 星期五 10时54分58秒
 > Other:        pipe1.c程序用数组files_pipes[]的两个文件描述符创建一个管道.
                 然后用文件描述符file_pipes[1]向管道中写数据,用文件描述符file_pipes[0]读回数据
				 管道有一些内置的缓存区,它在write和read调用之间保存数据
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main()
{
	/* data_processed存储返回值write和read调用的返回值 */
	int data_processed;
	/* 文件描述符组成的数组,file_pipes[0]用于读,file_pipes[1]用于写 */
	int file_pipes[2];
	const char some_data[] = "123";
	char buffer[BUFSIZ + 1];

	memset(buffer, '\0', sizeof(buffer));

	/* pipe函数在file_pipes[0]和file_pipes[1]创建一个管道 */
	if (pipe(file_pipes) == 0) {
		/* write函数从指针some_data所指的内存中写入strlen(some_data)个字节到file_pipes[1]所指的文件中
		 * 如果成功,则返回实际写入的字节数;如果失败,则返回-1,并将错误代码保存在errno中;此外返回0表示未写入任何数据 */
		data_processed = write(file_pipes[1], some_data, strlen(some_data));
		printf("Wrote %d bytes\n", data_processed);
		/* read函数从文件描述符file_pipes[0]指向的文件中读取BUFSIZ个字节到buffer指向的内存中
		 * 如果成功,则返回实际读取的字节数;如果失败,则返回-1,并将错误代码保存在errno中;此外返回0表示未读入任何数据,已经到达文件尾 */
		data_processed = read(file_pipes[0], buffer, BUFSIZ);
		printf("Read %d bytes: %s\n", data_processed, buffer);
		exit(EXIT_SUCCESS);
	}
	exit(EXIT_FAILURE);
}

程序运行结果如下所示:这个程序用数组file_pipes[]的两个文件描述符创建一个管道.然后用file_pipes[1]向管道中写数据,再用file_pipes[0]从管道读回数据.注意:管道有一些内置的缓存区,它在write和read调用之间保存数据看起来,这个例子毫无用处,因为在这个程序内可以直接从some_data向buffer复制数据,完全不需要使用pipe创建管道.管道的真正优势在于,如果想在两个进程传递数据的时候,当程序用fork调用创建新进程时,原先打开的文件描述符仍将保持打开状态.如果在原先的进程中创建一个管道,然后再调用fork创建新进程,即可通过管道在两个进程之间传递数据.两个进程之间的通信编写程序pipe2.c,在pipe1.c的基础上使用fork调用,实现两个进程之间的通信
/*************************************************************************
 > File Name:    pipe2.c
 > Description:  pipe2.c程序在父进程中创建一个管道,然后调用fork创建子进程,通过管道在父进程和子进程之间传递数据
 > Author:       Liubingbing
 > Created Time: 2015年07月10日 星期五 11时41分09秒
 > Other:        pipe2.c程序   父进程----file_pipes[1](向管道写数据)----file_pipes[0](从管道读回数据)----子进程
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main()
{
	int data_processed;
	int file_pipes[2];
	const char some_data[] = "123";
	char buffer[BUFSIZ + 1];
	pid_t fork_result;

	memset(buffer, '\0', sizeof(buffer));

	/* pipe函数用file_pipes文件描述符数组创建管道
	 * 用文件描述符file_pipes[1]向管道中写数据
	 * 用文件描述符file_pipes[0]从管道中读回数据 */
	if (pipe(file_pipes) == 0) {
		/* fork创建一个子进程
		 * 如果创建失败,返回-1
		 * 如果成功,返回0表示子进程pid
		 * 其他为父进程 */
		fork_result = fork();
		if (fork_result == -1) {
			fprintf(stderr, "Fork failure");
			exit(EXIT_FAILURE);
			}
		if (fork_result == 0) {
			/* 子进程中使用read系统调用从file_pipes[0]指向的文件中读取BUFSIZ个字节的数据到buffer指向的内存 
			 * 如果成功返回实际读取数据的字节数 */
			//sleep(2);
			data_processed = read(file_pipes[0], buffer, BUFSIZ);
			printf("Read %d bytes: %s\n", data_processed, buffer);
			exit(EXIT_SUCCESS);
		} else {
			/* 父进程中使用write系统调用从some_data指向的内存中读入strlen(some_data)个字节的数据到file_pipes[1]指向的文件 
			 * 如果成功返回实际读入数据的字节数 */
			data_processed = write(file_pipes[1], some_data, strlen(some_data));
			printf("Wrote %d bytes\n", data_processed);
		}
	}
	exit(EXIT_SUCCESS);
}
这个程序首先用pipe调用创建一个管道,接着用fork调用创建一个新进程.如果fork调用成功,父进程就写数据到管道中,而子进程从管道中读取数据.父子进程都在只调用了一次write或read之后就退出.如果父进程在子进程之前退出,就会在两部分输出内容之间看到shell提示符.如下所示(./a.out在子进程中添加sleep(2)):

这样结合pipe和fork就可以在不同的进程之间进行读写数据.


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

交叉编译参数 -I -L -l 详解

这里不管是你用gcc还是用arm-linux-gcc都是实用的。 当你下载一些freetype,libjpeg。你得先.configure,make make install  这里我主要讲一下一些参...

Linux 应用程序里面调用Shell

在Linux的应用程序里面调用我的shell(这玩意功能实在太强大)的办法有很多种一般来说有fork()、exec*()、pipe、system()其中又以system()调用很少方便,现在加以说明。...

《Linux程序设计》--读书笔记---第十三章进程间通信:管道

管道:进程可以通过它交换更有用的数据。 我们通常是把一个进程的输出通过管道连接到另一个进程的输入; 对shell命令来说,命令的连接是通过管道字符来完成的; cmd1    |     cmd2 ...

Linux程序设计学习笔记----进程间通信——管道

转载请注明出处: http://blog.csdn.net/suool/article/details/38444149, 谢谢! 进程通信概述 在Linux系统中,进程是一个独立的资源管...

《Linux程序设计》——进程间通信:管道

一、管道

Linux程序设计——进程间通信:管道

使用信号在进程间通信,传送的信息只限于一个信号值。更多的数据交换需要使用一种新的机制——管道。管道(pipe)把一个进程的输出连接到另一个进程的输入。 对shell命令的连接就是通过管道实现的,使用...
  • furney
  • furney
  • 2012年05月09日 09:52
  • 2287

Linux程序设计——进程间通信机制

信号量、共享内存和消息队列IPC(Inter-Process Communication,进程间通信)机制 信号量: 用于关联对资源的访问 共享内存: 用于在程序之间高效地共享数据 消息队列: ...

「邮槽」单向进程间通信——Console程序设计

创建本地邮槽—服务端/客户端—进行进程间通讯

LINUX 进程间通信程序设计

进程间通讯概述 目的 为什么进程间需要通信?         1、数据传输                 一个进程需要将它的数据发送给另一个进程。         2、资源共享     ...

LINUX 进程间通信程序设计-2

4、消息队列         消息队列就是一个消息的链表。可以把消息看作一个记录(具有特定的格式)。进程可以向消息队列按照一定的规则添加新消息;另一些进程则可以从消息队列中读走消息。 分类: ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux程序设计——pipe调用在两进程之间通信(第十三章)
举报原因:
原因补充:

(最多只允许输入30个字)