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

来源:互联网 发布:android listview优化 编辑:程序博客网 时间:2024/05/17 04:41
管道和有名管道是最早的进程间通信机制之一,管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。 管道是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;}



0 0
原创粉丝点击