Linux进程间通信
Posted Huang_ZhenSheng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux进程间通信相关的知识,希望对你有一定的参考价值。
目录
进程间通信的本质:让不同的进程,能看到同一份系统资源(系统通过某种方式提供的系统内存)
管道通信:
匿名管道 and 命名管道:底层的原理是基本一样的
匿名管道:
供具有血缘关系的进程,进行进程间通信(保证不同的进程,看到同一份资源)(常见于父子)
父子进程关闭不需要的文件描述符,来达到构建单向通信的信道的目的
这里有2个问题:
为什么需要关,那么曾经为什么要打开呢?
如果不打开读写,子进程拿到的文件打开方式必定和父进程一样,无法通信,同时更加灵活!
为什么要关闭?
一方面证明管道单向通信的特性,主要为了防止误操作
int pipe(int pipefd[2])
输出型参数,通过调用pipe,拿到刚刚打开的管道文件的描述符
2个fd,对应于一个读,一个写
代码演示:
#include<stdio.h>
2 #include<unistd.h>
3 #include<sys/wait.h>
4 #include<stdlib.h>
5 #include<string.h>
6 int main()
7
8 int pipe_fd[2] = 0;
9 if(pipe(pipe_fd) < 0)
10
11 perror("pipe");
12 return 1;
13
14
15 printf("%d,%d\\n",pipe_fd[0],pipe_fd[1]);
16
17 pid_t id = fork();
18 if(id < 0)
19
20 perror("fork");
21 return 2;
22
23 else if(id==0)
24
25 //child让子进程进行写入
26 close(pipe_fd[0]);
27
28
29 const char*msg = "我是子进程\\n";
30 int count = 5;
31 while(count)
32
33 write(pipe_fd[1],msg,strlen(msg));//向管道当中写入的功能
34 sleep(1);
35 count--;
36
37 close(pipe_fd[1]);
38 exit(0);
39
40 else
41 //child让父进行读取
42 close(pipe_fd[1]);
43 char buffer[64];
44 while(1)
45
46 buffer[0] = 0;
47 ssize_t size = read(pipe_fd[0],buffer,sizeof(buffer)-1);//管道中读取
48 if(size > 0)
49
50 buffer[size] = 0;
51 printf("从子进程中来的:%s\\n",buffer);
52
53 else if(size == 0)
54
55 printf("管道文件关闭,子进程退出\\n");
56 break;
57
58 else
59 break;
60
61
62 int status = 0;
63 if(waitpid(id,&status,0)>0)
64
65 printf("子进程退出,等待成功\\n");
66
67 close(pipe_fd[0]);
68
69 return 0;
70
管道的特性:
如果管道里面已经没有消息,父进程(读端)在干什么?
等待,在等管道内部有数据就绪
如果管道里面写端已经写满了,继续写入,还能写吗?
不能,等待管道内部有空闲空间(等父进程读走)
第一:管道自带同步机制
第二:管道是单向通信的
第三:管道是面向字节流的
第四:管道只能保证具有血缘关系的进程通信,常用于父子
第五:管道可以保证一定程度的数据读取的原子性
第六:进程退出,曾经打开的文件也会被关掉,管道也是文件,所以管道的生命周期随进程
验证部分特性:
read端 | write端 | 结果 |
不读 | 写 | write阻塞 |
读 | 不写 | read阻塞 |
读 | 不写 & 关闭 | read读取到0,文件结束! |
不读 & 关闭 | 写 | write被OS发送的SIGPIPE杀掉 |
读取关闭,一直在写
毫无意义,一直在写,本质就是在浪费系统资源,写进程会立马被OS终止掉!(通过发送信号终止子进程)
管道大小
64KB(非原子性写入管道当中的单元大小)
4KB(原子性写入的)
命名管道:
理解命名管道的原理
1:先保证两个进程能看到同一份资源
普通文件,是需要将数据刷新到磁盘的,持久化存储
命令行代码实验:
命名管道实现的相关代码:
Client端:
#include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6 #include<string.h>
7
8 #define FIFO "./fifo"
9 int main()
10
11 int fd = open(FIFO,O_WRONLY);
12 if(fd < 0)
13
14 perror("open");
15 return 2;
16
17 char buffer[128];
18 while(1)
19
20 printf("Please Enter");
21 fflush(stdout);
22 buffer[0] = 0;
23 ssize_t s = read(0,buffer,sizeof(buffer));//从标准输入里读数据
24 if(s > 0)
25
26 buffer[s] = 0;
27 write(fd,buffer,strlen(buffer));//写到管道文件
28
29 else if(s == 0)
30
31 printf("client quit\\n");
32 break;
33
34 else
35 break;
36
37
38 close(fd);
39 return 0;
40
server端:
#include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6
7 #define FIFO "./fifo"
8 int main()
9
10 int ret = mkfifo(FIFO,0644);
11 if(ret < 0)
12
13 perror("mkfifo");
14 return 1;
15
16 int fd = open(FIFO,O_RDONLY);
17 if(fd < 0)
18
19 perror("open");
20 return 2;
21
22 char buffer[128];
23 while(1)
24
25 buffer[0] = 0;
26 ssize_t s = read(fd,buffer,sizeof(buffer));
27 if(s > 0)
28
29 buffer[s] = 0;
30 printf("client : %s\\n",buffer);
31
32 else if(s == 0)
33
34 printf("client quit\\n");
35 break;
36
37 else
38 break;
39
40
41 close(fd);
42 return 0;
43
~
makefile:
client:client.c
5 gcc -o $@ $^
6 server:ser.c
7 gcc -o $@ $^
8 .PHONY:clean
9 clean:
10 rm -f client ser fifo
运行结果:
以上是关于Linux进程间通信的主要内容,如果未能解决你的问题,请参考以下文章