linux进程间通信 管道, 消息队列, 共享内存 信号(一)

进程间通信

之前进程之间交换信息的方法只能是经由fork或exec传送打开文件,或者通过文件系统。
下来将说明进程之间相互通信的其他技术—IPC(interProcess Commumication)
进程间通信IPC
IPC引入
IPC的方式通常有管道(包括无名管道和命名管道),消息队列,信号量,共享存储,Socket,Streams等,其中Socket和Streams支持不同主机上的两个进程IPC
一,管道
1.特点

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

2原理
当一个管道建立时,它会创建两个文件描述符:fd[0]为读而打开,fd[1]为写而打开。管道的建立存在与内核之中,如下图:
在这里插入图片描述
要关闭管道只需将这两个文件描述符关闭即可
在这里插入图片描述
3创建
单个进程中的管道几乎没有任何用处。所以,通常调用 pipe 的进程接着调用 fork,这样就创建了父进程与子进程之间的 IPC 通道。如下图所示:
在这里插入图片描述
创建管道
#include <unistd.h>
int pipe(int fd[2]); // 返回值:若成功返回0,失败返回-1

#include<stdio.h>
#include <unistd.h>
#include <string.h>

//int pipe(int pipefd[2]);
//int pipe(int fd[2]);

int main()
{
   
        int pid;
        char buf[128];
        int fd[2];
        if(pipe(fd) == -1)//建立管道      
         {
   
                printf("pipe create failed\n");
        }

        pid = fork();//建立子进程
        if(pid < 0)//建立子进程失败
        {
   
                printf("the child create failed\n");
        }
        else if(pid > 0)//父进程运行空间,pid>0时
        {
   
                printf("this is father\n");
                close(fd[0]);//父进程关闭读端文件描述符
                write(fd[1], "hello world", strlen("hello world\n"));//父进程对管道内写入
        }
        else if(pid == 0)//子进程运行空间,pid=0时
        {
   
                printf("this is child\n");
                close(fd[1]);//子进程关闭写端文件描述符
                read(fd[0], buf, 128);//子进程从管道内读出数据到buf
                printf("%s\n", buf);
        }
        return 0;
}

结果如下
在这里插入图片描述

FIFO 进程间通信第二种方式

特点
(1)FIFO可以在无关的进程之间交换数据,与无名管道不同。
(2)FIFO 有路径名(无名管道没有)与之相关联,它以一种特殊设备文件形式存在于文件系统中。
(3)管道中的数据被读走就没了,同时保持FIFO(先进先出的特点。
原理
与无名管道类似。
创建
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);// 返回值:成功返回0,出错返回-1
pathname是函数的名字
其中的 mode 参数与open函数中的 mode 相同(0600-读写)(open函数)。一旦创建了一个 FIFO,就可以用一般的文件I/O函数操作它。
当 open 一个FIFO时,==是否设置非阻塞标志(O_NONBLOCK)==的区别:

若没有指定O_NONBLOCK(默认)

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

实例

read.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
 #include <errno.h>
#include<string.h>
#include<stdlib.h>
#include <unistd.h>
  #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

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

int main()
{
   
        char buf[128];
        if((mkfifo("./file",0600)==-1) && errno!=EEXIST)//建立管道
        {
   
                printf("mkfifo failure\n");
                perror("why");
        }
        else  if(errno==EEXIST)
        {
   
                printf("file eexist\n");
        }
        else
        {
   
                printf("mkfifo successed\n");
        }
        int fd = open("./file", O_RDONLY);
        //打开管道,O_RDINLY-只读模式打开,如果没有另一个进程以只写模式打开管道,程序会阻塞此处
        int nread = read(fd, buf, 20);//从管道内读数据
        printf("read %d byte from fifo,context:%s\n",nread,buf);
        close(fd);//关闭管道
        return 0;
}

write.c
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include <errno.h>
#include <fcntl.h>
int main()
{
   
// ssize_t read(int fd, void *buf, size_t count);
        char *buf="hello world !!!!!!!!";
        int fd = open("./file",O_WRONLY);
        //打开管道,O_WRONLY-只写模式打开,如果没有另一个进程读它,程序会阻塞此处
        printf("write file success\n");
        write(fd,buf,strlen(buf));写入数据
       return 0;
}
~     

在这里插入图片描述
读的时候 不写那么读就会阻塞,知道写执行,才会读
上述例子可以扩展成 客户进程—服务器进程 通信的实例,
write的作用类似于客户端,可以打开多个客户端向一个服务器发送请求信息,
read类似于服务器,它适时监控着FIFO的读端,当有数据时,读出并进行处理,
每一个客户端必须预先知道服务器提供的FIFO接口,如下图。
在这里插入图片描述

消息队列的通信原理
消息队列(message queue)

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

特点

(1)消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级(链表存放的为结构体)。
(2)消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除(管道是读完就消失),除非销毁队列。
(3)消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取(链表的特性),也可以按消息的类型读取。
(4)没有固定的读端与写端,
双方进程都可以

原理

在这里插入图片描述

创建

了解了原理,我们则发现主要关心两个问题。
问题一:进程A如何添加消息队列
问题二:进程B如何读取消息队列

常用的api

1 #include <sys/msg.h>
2 // 创建或打开消息队列:成功返回队列ID,失败返回-1
3 int msgget(key_t key, int flag)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值