一、进程间通信
- 进程间通信的方式(ipc机制):管道、信号量、消息队列、共享内存、套接字。
- 利用我们学过的知识完成进程间通信用到的操作:一个程序像文件中写数据,用另一个文件来读取。
由此,如果我们能将数据写入内存中,效率将会高很多。所以我们可以用管道的方式来进行进程间通信。
1.进程间通信——管道
优点:
- 管道是一种直接想内存中写入数据和读取数据的工具。
- 管道是可以让读写数据进行同步控制的一种工具。
注意:
- 管道分为有名管道和无名管道。
- 写入管道的数据存储在内存中。
- 有名管道和无名管道的区别:有名管道可以在任意两个进程间通信,无名管道只能在父子进程间通信。
- 管道是一个半双工的通信方式。
(1)有名管道的创建
管道的创建有两种方式:命令式和函数式。
命令式创建管道的方式:mkfifo+管道名mkfifo fifo
图中可以看到管道文件的大小为0,无论管道中写没写数据,管道文件的大小都是0。因为管道是向内存中写数据的。
(2)有名管道的操作
管道的操作和文件的操作是相似的,都可以用读写操作对管道进行操作。
写操作
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>
int main()
{
int fdw=open("fifo",O_ERONLY);
assert(fdw!=-1);//正常情况下,fdr=3;
printf("dfw=%d\n",fdw);
while(1)
{
char buff[128]={0};
fgets(buff,128,stdin);
if((strncmp(buff,"end",3)==0)
{
break;
}
write(fdw,buff,strlen(buff));
}
close(fdw);
}
读操作
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>
int main()
{
int fdr=open("fifo",O_RDONLY); //有可能阻塞住;
assert(fdr!=-1);//正常情况下,fdr=3;
printf("dfr=%d\n",fdr);
while(1)
{
char buff[128]={0};
int n=read(fdr,buff,127);
if(n==0)
{
break;
}
printf("buff=%s\n",buff);
}
close(fdr);
}
发生阻塞和关闭程序的几种情况
- 正常情况下打开文件fdr和fdw的值都为3,因为0代表标准输入,1代表标准输出,2代表标准错误输出。
- 有名管道在读端打开的过程中有可能发生阻塞,因为有名管道是要两个进程同时打开的,并且一个进程以写的方式,一个进程以读的方式,如果只读取的话没有意义。
- 在读文件过程中,如果没有数据也会发生阻塞。
- 当管道满时,写端也会发生阻塞,等待数据读取之后再进行写入。
- 如果写端关闭,读端的返回值为0,读端也会关闭。
几种异常情况:
- 当正在通过管道执行的读写程序中,写程序强制退出程序之后,读程序也会退出。
- 当正在通过管道执行的读写程序中,读程序强制退出程序之后,写程序写入数据时,也会直接退出。因为出现异常,接受SIGPIGE信号,关闭了写端。
2.无名管道的创建
通过命令:pipe(int pipefd[2]) //pipefd[0]是读端,pipefd[1]是写端
这是规定。
无名管道的图解:
(1)无名管道的操作
注意:fork和获得描述符操作不可更改顺序,因为只有在有了读写描述符之后fork,子进程才也有权限。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>
int main()
{
int fd[2];
int rse=pipe(fd); //此操作之后获得读写描述符;
assert(rse!=-1);
pid_t pid=fork();
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);
}