笔记:进程间通信——消息传递(管道、FIFO、posix消息队列)

1.管道pipe

#include <unistd.h>

int pipe(int fd[2]);

管道的创建, fd[0]:从管道读;fd[1]:向管道写

管道是单个进程创建的,它却很少在单个进程内使用。管道的典型用途是:两个进程(一个父进程,一个子进程)提高进程间通信的手段。

步骤:

首先,父进程创建一个管道,fork一个自进程(子进程中也有该管道,管道相当与文件,子进程可以共享父进程的?);

然后,父进程关闭管道的读出端,子进程关闭同一个管道的写入端。

这样父子进程间变形成了一个单向的数据流,父进程写入,子进程读出。

2.popen和pclose函数

管道的通常用法是:创建一个管道连接到一个进程,然后读其输出或者向其中发送数据,为此,标准I/O库提供了两个函数popen和pclose函数。

#include <stdio.h>

FILE *popen(const char *cmdstring, const char *type);

int pclose(FILE *fp);

popen会先fork的一个子进程,然后exec 执行cmdstring, 如果type="r",则从子进程中读取,如果type=“w”,则通过管道向子进程中写


3.FIFO

管道没有名字,它只能用于有一个共同祖先进程的各个进程之间。两个无亲缘关系的进程间是不能通过管道进行IPC的。

在unix中,FIFO类似于管道,它是一个单向数据流,不同与管道的是,每个FIFO有一个路径名与之关联,从而无亲缘关系的进程访问同一个FIFO,可以进行IPC,

因此FIFO也称为有名管道。

#include <sys/types.h>

#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);创建一个新的FIFO,可以用open或者fopen打开pathname,要么为read,要么为write.

pathname是一个普通的unix路径名,它是该FIFO的名字。

管道或者FIFO的write总是往末尾追加数据,read则总是从开头返回数据。如果对管道或FIFO调用lseek,将会错误。

FIFO的使用
#define FIFO1 "/tmp/fifo.1"
#define FIFO2 "/tmp/fifo.2"
int main() {
   int readfd, writefd;
   pid_t childpid;
   if(mkfifo(FIFO1, FILE_MODE) < 0) && (errno != EEXIST))
   err_sys("can't create");
 if(mkfifo(FIFO2, FILE_MODE) < 0) && (errno != EEXIST))
   err_sys("can't create");
   if((childpid = Fork()) == 0) {
   readfd = open(FIFO1, O_RDONLY, 0);
   writefd = open(FIFO2, O_WRONLY, 0);
   server();...
   exit(0);
}
writefd = open(FIFO1, O_WRONLY, 0);
readfd = open(FIFO2, O_RDONLY, 0);
...
}

通过mkfifo创建FIFO的文件,然后打开文件的一些管段,关闭文件的一些端口,便可以进行数据的流通


总结:

管道和FIFO是许多应用程序的基本构建模块。管道普遍用于shell中,不过也可以从程序中使用,往往是用于父子进程之间回传信息。使用管道涉及(pipe, fork, close, exec, waitpid)可通过使用popen和pclose来避免,由它们处理具体细节并激活一个shell

FIFO与管道类似,但它们是用mkfifo创建的,之后需用open打开。

管道和FIFO的特征之一是,它们的数据是字节流,类似与TCP链接。


4.消息队列(posix消息队列和system V消息队列)

消息队列可认为是一个消息链表。每个消息都是一个记录,在某个进程往一个队列写入消息之前,并不需要另外某个进程在该队列上等待消息的到达。对管道和FIFO,除非读者已存在,否则先有写入者是没有意义的

队列中的每个消息有如下属性:

1.一个无符号整数优先级(posix)或者一个长整型类型(System V)

2.消息的数据部分长度

3.数据本身


1.创建一个新的消息队列或打开一个已存在的消息队列

#include <mqueue.h>
mqd_t mq_open(const char *name, int oflag, ...);
mqd_t mq_close(mqd_t mqdes);
mq_open()返回消息队列描述符

mq_close()其功能与关闭和打开文件的close()类似:调用进程可以不再使用该描述符,但其消息队列并不从系统中删除。

#incude <mqueue.h>
int mq_unlink(const char *name);
从系统中删除用作mq_open第一个参数的某个name,使用mq_unlink(name)

往一个队列中放置消息使用mq_send,从一个队列中读取出消息使用mq_receive





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值