目录
1.进程间通信的方法
(1)管道
(2)信号量
(3)共享内存
(4)消息队列
(5)套接字
2.IPC机制
1.有命管道:
1.简介
1.管道简介
|命令:
举例:ps -ef|grep "sleep"
两个进程通信,比如a,b进程,a向管道中写入数据,b读取数据;
管道的分类:有名管道和无名管道
区别:有名管道在任意两个进程间通信,无名管道在父子进程间通信;
2.有名管道的创建
创建的命令:mkfifo 管道名
打开管道:open();
读数据:read();
写入数据:write();
关闭管道:close();
3.有名管道演示进程间通信思考
如果进程 a 要将从键盘获取的数据传递给另一个进程 b, 用已具备的知识思考应该如何完成 ?
1.文件可以,但是不建议;
2.管道:
创建管道之后,它会在内存上分配一块空间,表面上看把数据写入管道中了,实际上是把数据写入内存中了。另外一个程序是从内存中读取数据的,所以效率是比较高的。
管道文件:大小永远为0;
4.有名管道实现进程间通信
又名命名管道;
代码:
a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
int main()
{
int fd = open("fifi", O_WRONLY);
assert(fd != -1);
printf("fd=%d\n", fd);
write(fd, "hello", 5);
close(fd);
}
b.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
int main()
{
int fd = open("./fifi", O_RDONLY);
assert(fd != -1);
printf("fd=%d\n", fd);
char buff[128] = { 0 };
read(fd, buff, 127);
printf("read:%s\n", buff);
close(fd);
}
结果:
5.管道的特点
(1)管道必须读,写进程同时open,否则会阻塞;
(2)如果管道中没有数据,那么read就会阻塞;
(3)管道的写端关闭,读read返回值为0
(4)管道打开的时候只有只读和只写方式,读写方式是未定义的;
6.循环写读
代码:
a.c
#include <string.h>
#include <assert.h>
#include <fcntl.h>
int main()
{
int fd = open("fifi", O_WRONLY);
assert(fd != -1);
while (1)
{
printf("input:\n");
char buff[128] = { 0 };
fgets(buff, 128, stdin);
if (strncmp(buff, "end", 3) == 0)
{
break;
}
write(fd, buff, strlen(buff));
}
close(fd);
}
b.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
int main()
{
int fd = open("./fifi", O_RDONLY);
assert(fd != -1);
printf("fd=%d\n", fd);
while (1)
{
char buff[128] = { 0 };
if (read(fd, buff, 127) == 0)
{
break;
}
printf("read:%s\n", buff);
}
close(fd);
}
结果:
2.无名管道
1.简介
无名管道,pipe创建无名管道;它只能进行父子间的通信;
使用pipe创建无名管道,只能进行父子间的通信;
pipe是一个系统调用
int pipe(int fds[2]);
//pipe()成功返回 0,失败返回-1
//fds[0]是管道读端的描述符
// fds[1]是管道写端的描述符
//规定
2.代码
父进程写入数据,子进程读取数据;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
int main()
{
int fd[2];
assert(pipe(fd)!=-1);
pid_t pid=fork();//先open,再frok,父子进程共享打开的文件描述符
assert(pid!=-1);
if(pid==0)
{
close(fd[1]);
char buff[128]={0};
read(fd[0],buff,127);
printf("child read:%s\n",buff);
close(fd[0]);
}
else
{
close(fd[0]);
write(fd[1],"hello",5);
close(fd[1]);
}
exit(0);
}
4.总体特点
(1)管道必须读,写进程同时open,否则会阻塞;
(2)如果管道没有数据,那么read也会阻塞;
(3)管道的写端关闭,读read返回值为0;
(4)管道打开的时候只有只读和只写两种方式,读写方式打开是未定义的;
(5)管道是半双工的(某一时刻只能选择一个方向)(面试重点)(通信方式有单工,半双工,全双工)
(6)无论有名还是无名,写入管道的数据都在内存中(面试重点)
(7)有名管道和无名管道的区别:有名可以在任意进程间通信,无名主要在父子进程间通信(面试重点)
(8)管道的读端关闭,写会产生异常(发送信号SIGPIPE)(可以改变信号的响应方式验证一下)
验证这个信息,只需要改变信号的响应方式:
#include <signal.h>
void fun(int sig)
{
printf("sig=%d\n",sig);
}
int main()
{
signal(SIGPIPE,fun);
...
}
5.管道实现图