管道-pipe函数-fdopen函数-popen函数详解-C语言

	管道和有名管道是最早的进程间通信机制之一,管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。 
管道是Linux支持的最初Unix IPC形式之一,具有以下特点:
 	管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
	 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
 	单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系 统,并且只存在与内存中。
 	数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
  	 #include <unistd.h>
  	 int pipe(int fd[2])  成功返回0,失败返回-1
管道在程序中用一对文件描述符表示,其中一个文件描述符有可读属性,一个有可写的属性。fds[0]是读,fds[1]是写。
	像文件操作有标准io流一样,管道也支持文件流模式。用来创建连接到另一进程的管道,是通过函数popen和pclose。
函数原型:
	#include <stdio.h>
	FILE* popen(const char* command, const char* open_mode);
	int pclose(FILE* fp);
	函数popen():允许一个程序将另一个程序作为新进程来启动,并可以传递数据给它或者通过它接收数据。command字符串是要运行的程序名。open_mode必须是“r”或“w”。如果open_mode是“r”,被调用程序的输出就可以被调用程序使用,调用程序利用popen函数返回的FILE*文件流指针,就可以通过常用的stdio库函数(如fread)来读取被调用程序的输出;如果open_mode是“w”,调用程序就可以用fwrite向被调用程序发送数据,而被调用程序可以在自己的标准输入上读取这些数据。
	函数pclose():用popen启动的进程结束时,我们可以用pclose函数关闭与之关联的文件流。

像文件操作有标准io流一样,管道也支持文件流模式。用来创建连接到另一进程的管道,是通过函数popen和pclose。
函数原型:
	#include <stdio.h>
	FILE* popen(const char* command, const char* open_mode);
	int pclose(FILE* fp);
	函数popen():允许一个程序将另一个程序作为新进程来启动,并可以传递数据给它或者通过它接收数据。command字符串是要运行的程序名。open_mode必须是“r”或“w”。如果open_mode是“r”,被调用程序的输出就可以被调用程序使用,调用程序利用popen函数返回的FILE*文件流指针,就可以通过常用的stdio库函数(如fread)来读取被调用程序的输出;如果open_mode是“w”,调用程序就可以用fwrite向被调用程序发送数据,而被调用程序可以在自己的标准输入上读取这些数据。
	函数pclose():用popen启动的进程结束时,我们可以用pclose函数关闭与之关联的文件流。
	fdopen函数  
	#include<stdio.h> 
	FILE * fdopen(int fildes,const char * mode); 
fdopen取一个现存的文件描述符(我 们可能从 o p e n , d u p , d u p 2 , f c n t lp i p e函数得到此文件描述符) ,并使一个标准的I / O流与该描述符相结合。此函数常用于由创建管道和网络通信通道函数获得的描述符。因为这些特殊类型的文件不能用标准I/O fopen函数打开,首先必须先调用设备专用函数以获得一个文件描述符,然后用f d o p e n使一个标准I / O流与该描述符相结合。   
fdopen()会将参数fildes 的文件描述符,转换为对应的文件指针后返回。参数mode 字符串   则代表着文件指针的流形态,此形态必须和原先文件描述词读写模式相同。

下面是一个使用管道实现的简单的通信。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
	char buf[1024];
	int fds[2],fds2[2]; //fds[0]用于读  fds[1]用于写
	pipe(fds);
	pipe(fds2);
	if(fork()>0)//父亲进程
	{
		close(fds[1]);//读的时候应先关闭写
		close(fds2[0]);   //写的时候先关闭读
		while(memset(buf,0,1024),read(fds[0],buf,1024)>0)//从管道读
		{
			write(1,buf,strlen(buf));      //read是一个阻塞函数,会一直停在这里
		}
		close(fds[2]);   //要使用close关闭管道  管道也会堵塞


		printf("father speaking:\n");
		FILE *fs=fdopen(fds2[1],"w");//管道与文件指针建立连接  可以不实用文件指针直接对管道操作
		if(fs==NULL)				//while(memset(buf,0,1024),read(0,buf,1024)>0)
		{							//{     write(fds[1],buf,strlen(buf));}
			perror("father died!\n");
		}
		while(memset(buf,0,1024),fgets(buf,1024,stdin)!=NULL)//输入buf中
		{
			fprintf(fs,"father message:%s",buf);//写入文件
			fflush(fs);
		}
		close(fds2[1]);		
		wait(NULL);
	}
	else
	{
		close(fds[0]);
		close(fds2[1]);//关闭写
		FILE *fd=fdopen(fds[1],"w");//管道当作一个文件
		if(fd==NULL)
		{
			perror("fdopen wrong\n");
		}
		while(memset(buf,0,1024),fgets(buf,1024,stdin)!=NULL)
		{
			fprintf(fd,"child message:%s",buf);
			fflush(fd);
		}
		close(fds[1]);

		while(memset(buf,0,1024),read(fds2[0],buf,1024)>0)
		{
			write(1,buf,strlen(buf));
		}
		close(fds2[0]);
		exit(1);
	}
	return 0;
}



发布了20 篇原创文章 · 获赞 6 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览