您的位置:首页 > 其它

进程间通信之管道

2016-02-24 17:23 204 查看


无名管道(pipe)

1,管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道

2,只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);

3,单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。

4,数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

管道创建:

管道由调用pipe函数而创建

#include<unistd.h>
intpipe(intfileds[2]);
#返回值:若成功则返回0,若出错则返回-1[/code]

经由参数filedes返回两个文件描述符:fileds[0]为读而打开,fileds[1]为写而打开,fileds[1]的输出是fileds[0]的输入。
但是单个进程中的管道没有什么用处。一般都是调用pipe的进程接着调用fork创建子进程,这样管道也相同的复制了一份到子进程,就创建了从父进程到子进程的IPC通道,如下图:





数据流方向:

父进程到子进程的管道,则父进程关闭管道的读端(fd[0]),子进程则关闭写端(fd[1]),如下图:





子进程到父进程的管道,则父进程关闭写端,子进程关闭读端。

当管道的一端被关闭后,下列两条规则起作用:
1,当读一个写端已被关闭的管道时,在所有数据都被读取后,read返回0,以指示达到了文件结束处
2,如果写一个读端已关闭的管道,则产生信号SIGPIPE
注:在写管道时,常量PIPE_BUF规定了内核中管道缓冲区的大小。如果对管道调用write,而且要求写的字节数小于等于PIPE_BUF,则此操作不会与其他进程对同一管道的write操作穿插进行。(主要发生在后续要讲的FIFO),用pathconf或者fpathconf函数可以确定PIPE_BUF的值。
示例:

#include"apue.h"
intmain(void)
{
intn;
intpipe_fd[2];
pid_tpid;
charr_buf[100];
charw_buf[4];
memset(r_buf,0,sizeof(r_buf));
memset(w_buf,0,sizeof(r_buf));
p_wbuf=w_buf;
if(pipe(pipe_fd)<0)
err_sys("pipeerror");
if((pid=fork())<0)
err_sys("forkerror");
elseif(pid>0)//parent
{
close(pipe_fd[0]);//read
strcpy(w_buf,"111");
if(write(pipe_fd[1],w_buf,4)!=-1)
printf("parentwriteover\n");
}
else//child
{
close(pipe_fd[1]);//write
n=read(pipe_fd[0],r_buf,100);
write(STDOUT_FILENO,line,n);
}
exit(0);
}


标准IO库函数:
在标准IO库中,为管道操作提供了两个函数(前面都是Unix环境下的库函数,标准库是跨平台的,在其他平台上仍能使用)

#include<stdio.h>
FILE*popen(constchar*cmdstring,constchar*type);#返回值:若成功则返回文件指针,若出错则返回NULL
intpclose(FILE*fp);#返回值:cmdstring的终止状态,若出错则返回-1


函数popen先执行fork,然后调用exec执行cmdstring,并且返回一个标准I/O文件指针。如果type是“r”,则文件指针连接到cmdstring的标准输出,如果type是“w”,则文件指针连接到cmdstring的标准输入。即执行popen,会先生成一个子进程来执行我们指定的程序,然后type是“r”,则子进程的标准输出会通过管道发送到原先进程,type是“w”,则原先进程通过管道发送给子进程的数据会成为子进程的标准输入。





而pclose函数则关闭标准IO流,等待命令执行结束,然后返回shell的终止状态。

命名管道(FIFO)

FIFO也是管道的一种,与无命名管道相比,FIFO可以用于不相关进程的数据交换。与前面提到pipe是一种文件一样,FIFO也是一种文件类型。
创建FIFO类似于创建文件,FIFO的路径名存在于文件系统中。(操作时,把FIFO看作文件即可,不同进程可以通过对FIFO读写,从而来实现进程通信)

#include<sys/stat.h>
intmkfifo(constchar*pathname,mode_tmode);#返回值:若成功则返回0,出错则返回-1


参数说明:

pathname:是FIFO的路径名称。
mode:与open打开文件的模式一样,例如“r”、“w”等。
注:一般的文件I/O函数(open、close、read、write等)都可以用于已经创建的FIFO。另外,一个给定的FIFO有多个写进程是很常见的,这样则有可能出现多个进程的所写的数据互相穿插。为避免数据穿插,则需要考虑原子操作。如上面所说,常量PIPE_BUF说明了可被原子地写到FIFO的最大数据量。
FIFO的用途:
1),FIFO由shell命令使用以便将数据从一条管道线传送到另一条,为此无需创建中间临时文件。
2),FIFO用于客户进程-服务器进程应用程序中,以在客户进程和服务进程之间传递数据。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: