进程间的五种通信方式(IPC):
1、管道(无名管道),速度慢,容量有限,只有父子进程能通讯;2、FIFO(命名管道),任何进程间都能通讯,但速度慢;3、消息队列,容量受到系统限制;4、信号量,不能传递复杂消息,只能用来同步;5、共享内存区。
一、管道:
管道:通常指无名管道,是UNIX系统中IPC最古老的形式。
1.特点:
它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。
它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)。
它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
2.原型:
#include <unistd.h>
int pipe(int pipefd[2]);
当一个管道被创建时,它会伴随着创建两个文件描述符,fd[0]
为读而打开,fd[1]
为写而打开。
如下图所示:
想关闭管道只要将两个文件描述符关闭即可。
3.用例说明:
单个进程中的管道几乎是没意义的,所以在调用pipe创建管道的时候,接着就调用函数fork()创建子进程,这样就实现了父进程与子进程之间的IPC方式。
(1)在使用fork()之后的半双工通信管道
(2)简单的从父进程到子进程之间的通信管道
直接上代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
//int pipe(int pipefd[2]);
int fd[2];
int pid;
char *wbuf = "hello word!";
char *rbuf = NULL;
if(pipe(fd) == -1)
{
printf("creat pipe error!\n");
}
pid = fork();
if(pid < 0)
{
printf("creat Process error!\n");
}
else if(pid > 0)
{
sleep(3);
printf("this is father process!\n");
close(fd[0]);
write(fd[1],wbuf,strlen(wbuf));
wait();
}
else
{
printf("this is child process!\n");
close(fd[1]);
rbuf = (char *)malloc(sizeof(char)*strlen(wbuf));
read(fd[0],rbuf,strlen(wbuf));
printf("read from father:%s\n",rbuf);
exit(0);
}
return 0;
}
结果:
按道理来说应该是父进程先执行的,但是在父进程那里执行了睡眠三秒,所以到子进程下面执行到read的时候发生了阻塞,直到父进程醒来写了东西进管道,子进程的read才继续执行。
二、FIFO(命名管道)
FIFO,也叫做命名管道,它是一种文件类型。
特点:
1.FIFO可以在无关进程之间交换数据,与无名管道不同。
2.FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。
FIFO原型:
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
返回值:
成功返回0,失败返回-1
温馨提示:如果文件已经存在即(EEXIST),这时候再重新创建文件的话也会是提示失败的。
其中的 mode 参数与 open 函数中的 mode 相同。一旦创建了一个 FIFO,就可以用一般的文件 I/O 函数操作它。

当 open 一个 FIFO 时,是否设置非阻塞标志(O_NONBLOCK)的区别:
其中的 mode 参数与 open 函数中的 mode 相同。一旦创建了一个 FIFO,就可以用一般的文件 I/O 函数操作它。
当 open 一个 FIFO 时,是否设置非阻塞标志(O_NONBLOCK)的区别:
若没有指定 O_NONBLOCK(默认),只读 open 要阻塞到某个其他进程为写而打开此 FIFO。类似的,只写 open 要阻塞到某个其他进程为读而打开它。
若指定了 O_NONBLOCK,则只读 open 立即返回。而只写 open 将出错返回 -1 如果没有进程已经为读而打开该 FIFO,其 errno 置 ENXIO。
上代码:
demo2.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
int main()
{
int ret;
ret = mkfifo("./file1",0600);
if(ret == 0)
{
printf("mkfifo pipe success!\n");
}else
{
printf("mkfifo pipe failed!\n");
perror("why");
}
return 0;
}
这样写的话当管道存在时,也会提示创建管道失败。
以下这样写就可以有效的避免打印多余的信息。
demo3.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
int main()
{
int ret;
ret = mkfifo("./file1",0600);
if(ret == -1 && errno != EEXIST)
{
printf("mkfifo pipe failed!\n");
perror("why");
}else
{
printf("mkfifo pipe success!\n");
perror("why");
}
return 0;
}
上面两部分的代码只是FIFO管道的创建的部分,真正的读端跟写端在以下的代码里体现:
read.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int ret;
int fd;
int n_read;
char *readBuf = NULL;
ret = mkfifo("./file1",0600);
if(ret == -1 && errno != EEXIST)
{
printf("Sorry,creat pipe error!\n");
}
else
{
printf("Congratulation,You creat pipe success!\n");
}
fd = open("./file1",O_RDONLY);
while(1){
readBuf =(char *)malloc(sizeof(char)*128);
n_read = read(fd,readBuf,128);
sleep(1);
printf("read from the write %d byte,the content is:%s\n",n_read,readBuf);
}
close(fd);
return 0;
}
以上代码是读端代码,在while循环里表示每隔一秒读一次,此时的读端open
是以O_RDONLY
只读的方式打开。这时候没有指定 O_NONBLOCK
即不阻塞操作,所以当没有写端写入时,这时候读端到read
时会被执行阻塞直到有写端的执行。
write.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int ret;
int cnt = 0;
int fd;
int n_write;
char *writeBuf = "hello I Love You";
ret = mkfifo("./file1",0600);
if(ret == -1 && errno != EEXIST)
{
printf("Sorry,creat pipe error!\n");
}
else
{
printf("Congratulation,You creat pipe success!\n");
}
fd = open("./file1",O_RDWR);
while(1){
n_write = write(fd,writeBuf,strlen(writeBuf));
printf("write %d byte to the file1,the content is:%s\n",n_write,writeBuf);
sleep(1);
cnt++;
if(cnt == 3)
{
break;
}
}
close(fd);
return 0;
}
这时候的读端的意思是每隔一秒写一次,直到写三次后退出循环,这时候的open
是以只写的方式O_WRONLY
打开,这时候没有指定 O_NONBLOCK
即不阻塞操作,所以当没有读端写入时,这时候写端写到write
时会被执行阻塞直到有读端的执行。
学习笔记,仅供参考!