进程间通信: 管道,信号量,存储空间,消息队列,套接字(SOCKET,网络编程)
在我们学习进程间通信之前,我们在进程之间都是用什么来进行数据传递的?显而易见,我们使用的是文件。不过我们的文本文件一般都是存储在磁盘中,所以我们在使用时,必须先把数据从磁盘中读取到内存中,然后cpu从内存中读取并做相应的处理。我们自己来感觉,这种方式是不是很浪费时间。所以我们就衍生出了第一种进程间通信的方式:
-------管道
管道是在内存中直接申请空间,并且直接在其中写入内存,直接从内存中读取。
管道常用的分为有名管道和无名管道两种;
有名管道:顾名思义,有名字的管道,这是我们需要申请一个有名字的管道文件,有名管道实现了无亲缘关系间的通信,原理是fifo提供了一个路径名与之关联,让fifo的文件存于系统中,只要知道该文件路径,就可以进行访问。fifo指代(fist in, fist out),即按照先进先出的工作。
有名管道的申请:mkfifo fp_name
通过在内存上开辟一块全新的空间, A, B 进程都通过文件描述符操作这块空
间。 以完成数据交互的功能。
1.2 有名管道
1.2.1 特性: 有名字的管道, 可以再任意两个进程间传递数据。
管道文件, 仅仅是目录树中的一个标示, 并不在磁盘上空间。
1.2.2 创建: mkfifo 命令 mkfifo();函数
1.2.3 使用:
打开: open
读取数据: read
写数据: write
关闭: close
1.2.4 管道文件操作特点:
如果一个进程以只写打开管道, 但是没有以只读或读写打开这个管道的进
程, 则打开操作会阻塞, 直到有进程以读或读写打开, open 才会返回。
如果一个进程以只读打开管道, 但是没有以只写或读写打开这个管道的进
程, 则打开操作会阻塞, 直到有进程以写或读写打开, open 才会返回。
当写端没有写入数据时, 读端会阻塞到 read 调用, 直到写端写入数据或
者写端关闭。
当管道没有空间时, 再写入数据就会被阻塞。 直到有进程读取数据, 或者
所有的读端关闭。
在同一个目录文件下,我们创建一个a.c 一个b.c 一个fifo的管道文件 ,用a.c文件编写,b.c文件读取,编写与读取的对象都是fifo这个管道文件。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>
#include<signal.h>
void fun(int sig)
{
printf("sig=%d",sig);
}
int main()
{
signal(SIGPIPE,fun);
int fd=open("fifo",O_WRONLY);
assert(fd !=-1);
printf("fd=%d\n",fd);
while(1)
{
char buff[128]={0};
printf("inputs: ");
fgets(buff,128,stdin);
if(strncmp(buff,"end",3)==0)
{
break;
}
write(fd,buff,127);
}
close(fd);
exit(0);
}
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<fcntl.h>
int main()
{
int fd=open("fifo",O_RDONLY);
assert(fd!=-1);
printf("fd=%d\n",fd);
char buff[128]={0};
int n=0;
while((n=read(fd,buff,127))>0)
{
printf("%d %s \n",n,buff);
memset(buff,0,128);
}
close(fd);
exit(0);
}
1、 无名管道
1.1 概念: 相对于有名管道而言, 其没有名称, 所以不能在任意进程之间使用,
只能应用于父子进程之间。 其原理是父子进程文件描述符共享。 所以, fork 之前创建、
打开无名管道。
1.2 创建并打开:
int pipe(int fd[2]);
fd[0] : 读端
fd[1] : 写端
1.3 操作:
读数据: read
写数据: write
关闭: close
1.4 操作特点
要在父子进程中分别关闭一个读文件描述符, 一个写文件描述符。
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<signal.h>
void main()
{
int fd[2];
pipe(fd);
pid_t t=fork();
assert(t!=-1);
if(t==0)
{
close(fd[1]);
while(1)
{
char buff[128]={0};
int n=0;
if(( n=read(fd[0],buff,127))==0)
{
break;
}
printf("child buff is %s \n",buff);
}
close(fd[0]);
}
else
{
close(fd[0]);
while(1)
{
char buff[128]={0};
//memset(buff,0,127);
printf("inputs :\n");
fgets(buff,128,stdin);
if(strncmp(buff,"end",3)==0)
{
break;
}
write(fd[1],buff,strlen(buff));
}
close(fd[1]);
}
//exit(0);
}
管道的写端彻底关闭,读端返回一个0,
管道的读端彻底关闭,写数据会引发异常,也就收到SIGPIPE