进程间通信---管道

来源:互联网 发布:me042j a支持什么网络 编辑:程序博客网 时间:2024/05/23 20:05

文章模块:

1.进程间通信的实质
2.管道
3.管道的特点
4.管道的四种情况
5.命名管道
6.匿名管道的代码实现
7命名管道的代码实现

一、进程间通信的实质

      每个进程都有各自不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到。所以进程之间要交换数据必须要通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间考到内核缓冲区,进程2载从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信。

如图:

二、管道

管道是一种最基本的IPC机制,由pipe函数创建。

调用pipe函数,在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端和一个写端,然后通过函数参数传出给用户程序两个文件描述符,filedes[0]指向管道的读端,filedes[1]指向管道的写端。所以,管道在用户程序看起来就像一个打开的文件。可通过read、write函数向文件读写数据。向这个文件读写数据其实是在读写内核缓冲区。pipe函数调用成功返回0,失败返回-1。

pipe函数的调用过程:

1.父进程创建管道

2.创建一个子进程

3.父进程关闭读端fd[0],子进程关闭写端fd[1]


     父进程调用pipe函数开辟管道,得到两个文件描述符指向管道的两端。


    父进程调用fork创建一个子进程,子进程继承父进程的文件描述符集,则子进程也有两个文件描述符指向同一管道的两端。


    父进程关闭管道读端,子进程关闭管道写端。父进程可以往管道里写,子进程可以从管道里读。管道是用环形队列实现的,数据从写端流入,从读端流出。这样就实现了进程间通信。

三、管道的特点

1.只能单向通信

2.匿名管道只适用于具有血缘关系的进程间通信

3.依赖于文件系统,生命周期随进程

4.自带同步功能,防止读到垃圾数据,以互斥为前提

5.基于无格式字节流

6.管道的缓冲区是有限的(管道存在于内存中,在管道创建时,为缓冲区分配一个页面大小)

下面解释一下

为什么管道只能单向通信?

          来看下Linux的实现,数据只能单向移动的意思是FIFO,于是Linux实际中构建了一个循环队列。具体的则是,在内核申请一个缓冲区,作为pipe()操作中匿名管道的实体,缓冲区设置两个指针,一个读指针,一个写指针。并保证读指针向前移动不能超过写指针,否则唤醒写进称并让读指针睡眠,直到读满需要的字节数。同理,读指针向前移动也不能超过写指针,否则唤醒写进程并让读进程睡眠,直到写满要求的字节数。说白了,管道在操作系统内部就是一个环形队列。

pipe()返回的两个文件句柄最后指向的其实是一个inode,只不过是一个read only一个是write only。试想同时有两个进程读[或者写,假设只有两个进程]的后果。由于i_count会等于2--如果小于2则说明两个进程同时关闭了写句柄,因此会退出读函数。此时两个进程会分别认为对方才是写者而反复醒来,反复监测,然而没有数据,于是反复睡眠。如果有多个进程,两进程同时读[或者写],会造成数据混乱,因为读指针只有一个,而你不能保证读写的顺序。

所以,想要使用管道完成双向通信,只需要创建两个管道就可以了。

为什么管道只适用于有血缘关系的进程间通信?

     因为管道是通过文件描述符来控制数据读写的。所以只有血缘关系的进程才会产生指向同一个管道的文件描述符。

管道容量是多少?

     用命令 ulimit -a可以查看,----->512Bytes*8 = 4096Bytes

     也可以用程序代码验证

四、管道的四种情况

1.读端不读了,但不关闭读文件描述符,当管道写满时

如果指向管道读端的文件描述符没有关闭,(管道写端的引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程从管道的写端写数据,那么管道在被写满时再次write会阻塞,直到管道中有了空位置才写入数据并返回。

2.写端不写了,但不关闭写文件描述符,当管道中数据读完

如果指向管道写端的文件描述符没有关闭,(管道写端的引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会被阻塞,直到管道中有数据可读了才会读取数据并返回。

3.写端一直写,读端关闭读文件描述符

如果所有指向管道读端的文件描述符都关闭了,(管道写端的引用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。

4.读端一直读,写端关闭写文件描述符

如果所有指向管道写端的文件描述符都关闭了,(管道写端的引用计数等于0),而仍有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。

1、2体现了同步机制

五、命名管道 FIFO

可以用于两个无血缘关系的进程间通信。命名管道和管道不通的在于它提供一个路径名与之关联,以FIFO的文件形式存储于2文件系统中,命名管道是一个设备文件,因此,即使进程与创建命名管道的进程之间无任何血缘关系,只要可以访问该路径,就能够通过命名管道相互通信。命名管道总是按照先进先出的原则工作。

六、代码实现--------------匿名管道

mypipe

/*************************************************************************> File Name: mypipe.c> Author: ZX> Mail: 18829897183@163.com > Created Time: Sat 13 May 2017 06:49:35 PM PDT ************************************************************************/#include <stdio.h>#include <unistd.h>#include <string.h>int main(){int fd[2];int ret = pipe(fd);if(ret < 0){perror("pipe failed");}pid_t id = fork();if(id == 0){//childclose(fd[0]);//write -- close readint i = 0;char* msg = "hello world!";while(i < 10){ssize_t s = write(fd[1], msg, strlen(msg));printf("i am writing! %d\n",i++);fflush(stdout);}}else{//father//close(fd[1]);//char buf[1024];//while(1)//{//ssize_t s = read(fd[0], buf, sizeof(buf));//if(s > 0)//{//buf[s] = 0;//printf("father read: %s\n", buf);//}//if(s == 0)//{//printf("end of file!\n");//}//}int status = 0;waitpid(id, &status, 0);}return 0;}


七、代码实现--------命名管道

server

/*************************************************************************> File Name: server.c> Author: ZX> Mail: 18829897183@163.com > Created Time: Sat 13 May 2017 07:26:10 PM PDT ************************************************************************/#include <stdio.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>#include <unistd.h>#include <string.h>int main(){int ret = mkfifo("./mypipe", S_IFIFO | 0666);if(ret < 0){perror("mkfifo failed!");return 1;}int fd = open("./mypipe", O_RDONLY);if(fd < 0){perror("open failed!");return 2;}else{while(1){char buf[1024];memset(buf, '\0', sizeof(buf));ssize_t s = read(fd, buf, sizeof(buf));if(s > 0){buf[s-1] = 0;printf("server read:%s", buf);}else if(s == 0){printf("client closed!server is closing!\n");break;}}}return 0;}
/*************************************************************************> File Name: client.c> Author: ZX> Mail: 18829897183@163.com > Created Time: Sat 13 May 2017 07:26:10 PM PDT ************************************************************************/#include <stdio.h>#include <string.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>#include <unistd.h>int main(){int fd = open("./mypipe", O_WRONLY);if(fd < 0){perror("open failed!");return 1;}else{while(1){printf("Please Enter: ");fflush(stdout);char msg[1024];memset(msg, '\0', sizeof(msg)-1);ssize_t s = read(0, msg, sizeof(msg));write(fd, msg, sizeof(msg));}}return 0;}










原创粉丝点击