进程间通信
前提引入: 我们之前接触过管道 | 将前一个命令的输出结果作为后一个命令的输入
如:ps | grep “sleep”
其实就是将 ps 的结果写入到一个区域,在从这个区域读出目标数据
有名管道
mkfifo
创建管道文件 : mkfifo fifo ->创建一个名为fifo的管道文件
如图,管道文件的大小为0,是因为他是在内存中写入,读取,并不会占用磁盘空间,因此速度会快很多。
管道文件只有:只读,只写两种权限。
1.执行写入文件a.c
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>int main()
{int fd = open("fifo",O_WRONLY);if(fd == -1){printf("none file\n");exit(1);}char buff[128];while(1){printf("intput:");fflush(stdout);fgets(buff,128,stdin);buff[strlen(buff)-1]=0;if(strcmp(buff,"end") == 0){break;}write(fd,buff,strlen(buff));}close(fd);exit(0);
}
2.执行读取文件 b.c
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>int main()
{int fd = open("fifo",O_RDONLY);if(fd == -1){printf("none file\n");exit(1);}printf("fd = %d\n",fd);while(1){char buff[128]={0};int n = read(fd,buff,127);if(n != 0){printf("%s\n",buff);}else{break;}}close(fd);exit(0);
}
管道文件必须同时被只读,只写打开,否则无法成功打开
1.只写无法打开
2.只读无法打开
3.正确方式:只读,只写同时打开
写端关闭,读端read返回0,退出循环
读端关闭,写端write时会收到异常信号(SIGPIPE),进而结束该进程
验证是否产生该信号
写端a.c 测试代码:
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>void fun_sig(int sig)
{printf("%d,%d\n",sig,13 == sig);
}
int main()
{signal(SIGPIPE,fun_sig);int fd = open("fifo",O_WRONLY);if(fd == -1){printf("none file\n");exit(1);}char buff[128];while(1){printf("intput:");fflush(stdout);fgets(buff,128,stdin);buff[strlen(buff)-1]=0;if(strcmp(buff,"end") == 0){break;}write(fd,buff,strlen(buff));}close(fd);exit(0);
}
如图:
有名管道能在任意两个进程间使用
无名管道
利用函数 int pipe(int fds[2]);
int pipe(int fds[2]);
pipe()成功返回 0,失败返回-1
fds[0]是管道读端的描述符
fds[1]是管道写端的描述符
测试代码:
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>int main()
{int fd[2];if(pipe(fd) == -1) exit(1);int pid = fork();if(pid == 0){close(fd[0]);printf("child input\n");write(fd[1],"hello",6);}else{char buff[128]={0};close(fd[1]);printf("parent read:");read(fd[0],buff,127);printf("%s\n",buff);}exit(0);
}
如图:
无名管道主要应用于父子进程间的通信。
管道的特点
◼ 无论有名还是无名,写入管道的数据都在内存中
◼ 管道是一种半双工通信方式(通信方式有单工、半双工、全双工)
◼ 有名和无名管道的区别:有名可以在任意进程间使用,而无名主要在父子进程间