目录
进程间通信的本质:让不同的进程,能看到同一份系统资源(系统通过某种方式提供的系统内存)
管道通信:
匿名管道 and 命名管道:底层的原理是基本一样的
供具有血缘关系的进程,进行进程间通信(保证不同的进程,看到同一份资源)(常见于父子)

父子进程关闭不需要的文件描述符,来达到构建单向通信的信道的目的
这里有2个问题:
为什么需要关,那么曾经为什么要打开呢?
如果不打开读写,子进程拿到的文件打开方式必定和父进程一样,无法通信,同时更加灵活!
为什么要关闭?
一方面证明管道单向通信的特性,主要为了防止误操作
int pipe(int pipefd[2])
输出型参数,通过调用pipe,拿到刚刚打开的管道文件的描述符
2个fd,对应于一个读,一个写
- #include
- 2 #include
- 3 #include
- 4 #include
- 5 #include
- 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:先保证两个进程能看到同一份资源
普通文件,是需要将数据刷新到磁盘的,持久化存储

- #include
- 2 #include
- 3 #include
- 4 #include
- 5 #include
- 6 #include
- 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 }
- #include
- 2 #include
- 3 #include
- 4 #include
- 5 #include
- 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 }
- ~
- client:client.c
- 5 gcc -o $@ $^
- 6 server:ser.c
- 7 gcc -o $@ $^
- 8 .PHONY:clean
- 9 clean:
- 10 rm -f client ser fifo
