您的位置:首页 > 其它

进程间通信——管道

2018-03-25 12:32 176 查看
一、进程间通信
1、本质:让两个不相干的进程看到同一块资源,这个资源肯定是操作系统提供的
2、目的
    ·数据传输:一个进程需要将它的数据发给另一个进程
    ·资源共享:多个进程之间共享同样的资源

    ·通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(例如:子进程终止时要通知父进程)
    ·进程控制:有些进程希望完全控制另一个进程的执行,此时控制进程希望能够拦截另一个进程所有陷入和异常,并能够及时知道它的状态改变
3、分类
(1)管道
    ·匿名管道

    ·命名管道

(2)System V IPC
    ·System V 消息队列

    ·System V 共享内存

    ·System V 信号量

(3)POSIX IPC
    ·消息队列

    ·共享内存

    ·信号量

    ·互斥量

    ·条件变量

    ·读写锁

二、管道
1、概念
    ·管道是Unix中最古老的进程间通信的形式

    ·从一个进程链接到另一个进程间的一个数据流



2、匿名管道:创建一个无名管道
int pipe(int fd[2]);
其中:fd为文件描述符数组,fd[0]表示读端,fd[1]表示写端
          成功返回0,失败返回错误代码



1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<unistd.h>
5
6 int main()
7 {
8 int fds[2];
9 char buf[100];
10 int len;
11
12 if(pipe(fds) == -1){
13 perror("make pipe"),exit(1);
14 }
15 //read from stdin
16 while(fgets(buf,100,stdin)){
17 len = strlen(buf);
18 //write into pipe
19 if(write(fds[1],buf,len) != len){
20 perror("write to pipe");
21 break;
22 }
23 memset(buf,0x00,sizeof(buf));
24 //read from pipe
25 if((len = read(fds[0],buf,100)) == -1){
26 perror("read from pipe");
27 break;
28 }
29 //write to stdout
30 if(write(1,buf,len) != len){
31 perror("write to stdout");
32 break;
33 }
34 }
35 }



3、用fork来共享管道原理
(1)父进程创建管道(父进程调用pipe开辟管道,得到两个文件描述符分别指向管道的读端和写端)



(2)父进程fork出子进程(父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一个管道)



(3)父进程关闭fd[0],子进程关闭fd[1](父进程关闭管道读端,子进程关闭管道写端。父进程往管道里写,子进程从管道里读。管道是用环形队列实行的,数据从写端流入,从读端流出,这样就实现了进程间通信)



1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<unistd.h>
5
6 int main()
7 {
8 int fds[2];
9 if(pipe(fds) == -1){
10 perror("pipe");
11 return 1;
12 }
13 pid_t pid = fork();
14 if(pid < 0){
15 perror("fork");
16 return 2;
17 }
18 else if(pid > 0){//parent write
19 close(fds[0]);
20 char *argv = "child , I am your father";
21 int i = 4;
22 while(i--){
23 write(fds[1],argv,strlen(argv));
24 sleep(1);
25 }
26 }
27 else{//child read
28 close(fds[1]);
29 char buf[1024];
30
31 while(1){
32 size_t s = read(fds[0],buf,sizeof(buf));
33 if(s > 0){
34 buf[s] = 0;
35 printf("child : %s\n",buf);
36 }
37 else if(s == 0){
38 printf("child : parent did not speak!\n");
39 break;
40 }
41 else{
42 perror("read");
43 return 3;
44 }
45 }
46 }
47 return 0;
48 }


4、管道读写规则



5、匿名管道的特点
(1)只有用于具有共同祖先的进程(具有亲缘关系的进程)之间通信;通常一个管道由一个进程创建,然后该进程调用fork,此后,父子进程之间就可以应用该管道
(2)管道可以提供流式服务
(3)一般情况,进程退出,管道释放,所以管道的生命周期随进程
(4)一般而言,内核会对管道操作进行同步和互斥
(5)管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道
6、命名管道
·管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信
·如果我们想在不想关的进程之间交换数据,可以使用FIFO文件来工作,它被称为命名管道
·命名管道是一种特殊类型的文件
创建命名管道
*可以从命令行上创建,命令行方法是使用命令:
mkfifo filename



*可以从程序里创建,相关函数: 1 #include<sys/types.h>
2 #include<sys/stat.h>
3
4 int mkfifo(const char *filename,mode_t mode);返回值:成功返回0,失败返回-1
参数:filename为创建出的管道名称
          mode为这个管道具有的权限 1 #include<sys/types.h>
2 #include<sys/stat.h>
3 #include<stdio.h>
4
5
6 int main()
7 {
8 if(mkfifo("fifo",0644) == -1){
9 perror("mkfifo");
10 return 1;
11 }
12 return 0;
13 }



7、匿名管道和命名管道的区别
(1)匿名管道由pipe函数创建
(2)命名管道由mkfifo函数创建,打开用open
(3)FIFO(命名管道)与pipe(匿名管道)之间唯一的区别是打开的方式不同,一旦这些工作完成之后,它们具有相同的语义
例:用命名管道实现
Makefile文件 1 .PHONY:all
2 all:client server
3 client:client.c
4 gcc client.c -o client
5 server:server.c
6 gcc server.c -o server
7 .PHONY:clear
8 clear:
9 rm -f client server
client.c 1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6 #include<stdlib.h>
7 #include<string.h>
8
9 #define ERR_EXIT(m)\
10 do{\
11 perror(m);\
12 exit(EXIT_FAILURE);\
13 }while(0)
14 int main()
15 {
16 int wfd = open ("mypipe",O_WRONLY);
17 if ( wfd < 0 ){
18 ERR_EXIT("open");
19 }
20 char buf[1024];
21 while(1){
22 buf[0] = 0;
23 printf("please enter : ");
24 fflush(stdout);
25 ssize_t s = read (0,buf,sizeof(buf)-1);
26 if ( s > 0 ){
27 buf[s] = 0;
28 write(wfd,buf,strlen(buf));
29 }
30 else if(s <= 0){
31 ERR_EXIT("read");
32 }
33 }
34 close(wfd);
35 return 0;
36 }
server.c 1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6 #include<stdlib.h>
7
8 #define ERR_EXIT(m)\
9 do{\
10 perror(m);\
11 exit(EXIT_FAILURE);\
12 }while(0)
13 int main()
14 {
15 umask(0);
16 if ( mkfifo("mypipe",0644) < 0){
17 ERR_EXIT("mkfifo");
18 }
19 int rfd = open ("mypipe",O_RDONLY);
20 if ( rfd < 0 ){
21 ERR_EXIT("open");
22 }
23 char buf[1024];
24 while(1){
25 buf[0] = 0;
26 printf("please wait...\n");
27 ssize_t s = read (rfd,buf,sizeof(buf)-1);
28 if ( s > 0 ){
29 buf[s-1] = 0;
30 printf("client say : %s\n",buf);
31 }
32 else if(s == 0){
33 printf("client quit,exit now!\n");
34 exit(EXIT_SUCCESS);
35 }
36 else{
37 ERR_EXIT("read");
38 }
39 }
40 close(rfd);
41 return 0;
42 }测试结果:
(1)先运行server,创建出mypipe
(2)再运行client,输入数据进行交流

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: