六种进程间通信方式详解

进程间通信是指在不同进程之间传播或交换信息。

IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享内存Socket、Streams等。其中Socket和Streams支持不同主机上的两个进程IPC。

一、管道

管道,通常指无名管道,是UNIX系统IPC最古老的形式。

1、特点

  •  它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。
  • 它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)。
  • 它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。 

2、原型

#include <unistd.h>

int pipe(int pipefd[2]);

pipefd[2]    用于存放读和写的文件描述符  大小为2的数组

返回值:成功返回 0   失败返回-1 ,errno被设置

        当一个管道建立时,它会创建两个文件描述符:fd[0]为读而打开,fd[1]为写而打开(巧记:我们说话时说01和读写,0对应读,1对应写)。如下图:

 3、demo1

思路:

  • pipe创建管道
  • fork创建进程
  • 父进程往管道里写,子进程读管道里的数据并打印
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main()
{
        int pid;
        int fd[2];
        char r_buf[128] = {0};

        if ((pipe(fd)) == -1) {		//创建管道
                perror("pipe fail");
                exit(-1);
        }

        if ((pid = fork()) == -1) {		//创建进程
                perror("fork fail");
                exit(-1);
        }

        if (pid > 0) {		//父进程
                close(fd[0]);	//关闭读端
                write(fd[1], "hallo world!", strlen("hallo world!"));	//往管道里写
                close(fd[1]);	//关闭管道
        } else if (pid == 0) {
                close(fd[1]);	//关闭写端
                read(fd[0], r_buf, 128);	//读取管道中的数据
                printf("%s\n", r_buf);		//打印数据
                close(fd[0]);		//关闭管道
        }

        return 0;
}

运行结果:

二、FIFO

FIFO,也称为命名管道,它是一种文件类型。

1、特点

  • FIFO可以在无关的进程之间交换数据,与无名管道不同。
  • FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。 

2、原型

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);

pathname	创建一个名字为"pathname"的FIFO特殊文件
mode	文件权限

返回值:成功返回 0   失败返回 -1 ,errno被设置

        其中的mode参数与open函数中的mode相同。一旦创建了一个FIFO,就可以用一般的文件I/O函数操作它。当open一个FIFO时,是否设置非阻塞标志(O_NONBLOCK)的区别:

  • 若没有指定O_NONBLOCK(默认),只读open要阻塞到某个其他进程为写而打开此FIFO。类似的,只写open要阻塞到某个其他进程为读而打开它。
  • 若指定了O_NONBLOCK,则只读open立即返回,而只写open将出错返回 -1,如果没有进程已经为读而打开该FIFO,其errno置ENXIO。

3、demo

         FIFO的通信方式类似于在进程中使用文件来传输数据,只不过FIFO类型文件同时具有管道的特性。在数据读出时,FIFO管道中同时清除数据,并且“先进先出”。下面的例子演示了使用FIFO进行IPC的过程。

思路:

  • mkfifo创建FIFO
  • fork创建进程
  • 父进程只写打开FIFO,并往FIFO里写如数据
  • 子进程只读打开FIFO,并读取FIFO里的数据并打印
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>

int main()
{
        int fd;
        int pid;
        int sum = 3;
        char r_buf[128] = {0};

        if (((mkfifo("file", 0600)) == -1) && (errno != EEXIST)) {	//创建FIFO,如果FIFO存在条件为假
                perror("mkfifo fail");
                exit(-1);
        }

        if ((pid = fork()) == -1) {	//创建进程
                perror("fork fail");
                exit(-1);
        } else if (pid > 0) {	//父进程
                fd = open("file", O_WRONLY);	//打开FIFO
                while(sum)	//间隔一秒往FIFO里写入数据
                {
                        write(fd, "message form fifo", strlen("message from fifo"));
                        sleep(1);
                        sum--;
                }
                close(fd);	//关闭FIFO
        } else if (pid == 0) {	//子进程
                fd = open("file", O_RDONLY);	//打开FIFO
                while (sum)		//间隔一秒读取一次FIFO里的数据并打印
                {
                        read(fd, r_buf, 128);
                        puts(r_buf);
                        sleep(1);
                        sum--;
                }
                close(fd);	//关闭FIFO
        }

        return 0;
}

运行结果:

三、消息队列

消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。

1、特点

  •  消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
  • 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
  • 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。 

 2、原型

//头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);
//创建或打开队列,成功返回队列ID,失败返回-1,errno被设置

int msgsnd(int msqid, const void *msgp, size_t msgsz, int flag);
//写入数据,成功返回0,失败返回-1, errno被设置

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int flag);
//读取数据,成功返回数据的字节数,失败返回-1, errno被设置

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//根据cmd(删除队列、设置数据元素、读取数据结构)命令执行操作。失败返回-1,errno被设置
key ftok()生成,key为队列ID的组成部分
msgflg 标志位(IPC_CREAT、IPC_EXCL、 IPC_NOWAIT)还应加上队列权限(读、写、执行)
msqid 队列ID
msgp 消息缓冲区指针(结构体指针)
flag 为0表示阻塞方式(队列空间不够就会堵塞),设置IPC_NOWAIT 表示非阻塞方式
msgsz 消息数据长度,不含数据类型长度4个字节
msgtyp 数据类型 type == 0 返回队列中的第一个消息。type >
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值