https://blog.csdn.net/wh_sjc/article/details/70283843
1.无名管道
1.1 管道大多数为半双工通信
1.2 管道只能在具有公共祖先的两个进程中使用,通常,一个管道由一个进程创建,在进程调用fork之后,这个管道就能在父子进程中通信
1.3 管道通过pipe调用的 int pipe(int fd[2])
fd[0] 表示读 fd[1] 表示写 ,由于半双工通信机制,一个进程读的时候关闭写,写的时候关闭读
#include "apue.h"
int main()
{
int n;
int fd[2];
pid_t pid;
char line[MAXLINE];
if(pipe(fd)<0)
err_sys("pipe error");
if ((pid = fork())<0)
{
err_sys("fork error");
}
else if (pid>0)
{
close(fd[0]);
write(fd[1],"hello world\n",12);
}
else
{
close(fd[1]);
n = read(fd[0],line,MAXLINE);
write(STDOUT_FILENO,line,n);
}
exit(0);
}
result:
hello world
2 命名管道 FIFO
2.1 无名进程只能在两个相关的进程间通信,有名管道在不相关的进程中也能通信
2.2 示例
pipe_read.sh 输出管道内容
pipe_write.sh 向管道中写入内容
pipe_read.sh:
if [ ! -p /tmp/pipe1 ];then
cd /etc
mknod /tmp/pipe1 p
fi
while :
do
read msg
if [ "$msg" = "" ];then
continue
else
echo $msg
fi
done </tmp/pipe1
pipe_write.sh:
while :
do
echo "Enter your name: \c"
read name
today=`date`
echo "$name $today" >/tmp/pipe1
done
结果:
区别:
从结构上看,无名管道没有文件路径名,不占用文件目录项,因此文件目录结构中的链表不适用于这种文件,它只是存在于打开文件结构中的一个临时文件,随其所依附的进程的生存而生存,当进程终止时,无名管道也随之消亡。送入管道的信息一旦被读进程取用就从管道中消失了,读写操作之间符合先进先出的队列原则(有名管道也是)。有名管道类似文件,除非主动删除,否则一直存在。
3.消息队列
3.1简介
消息队列是消息的链接表,存储在内核中,由消息队列标识符标识。msgget创建或者打开一个队列,msgsnd将新消息添加到队列尾端
3.2 消息队列特点
1.管道只能依照先进先出的顺序通信,消息队列还可以按照消息的类型字段取消息
2.消息队列独立于消息发送或者接收进程,进程结束,消息队列及其内容不会被删除
3. msgsnd(msqid, &msg, sizeof(msg.mtext), 0); 发送消息
msgrcv(msqid, &msg, 256, 999, 0); 接收消息
msg_service.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
// 用于创建一个唯一的key
#define MSG_FILE "/etc/passwd"
// 消息结构
struct msg_form {
long mtype;
char mtext[256];
};
int main()
{
int msqid;
key_t key;
struct msg_form msg;
// 获取key值
if((key = ftok(MSG_FILE,'z')) < 0)
{
perror("ftok error");
exit(1);
}
// 打印key值
printf("Message Queue - Server key is: %d.\n", key);
// 创建消息队列
if ((msqid = msgget(key, IPC_CREAT|0777)) == -1)
{
perror("msgget error");
exit(1);
}
// 打印消息队列ID及进程ID
printf("My msqid is: %d.\n", msqid);
printf("My pid is: %d.\n", getpid());
// 循环读取消息
for(;;)
{
msgrcv(msqid, &msg, 256, 888, 0);// 返回类型为888的第一个消息
printf("Server: receive msg.mtext is: %s.\n", msg.mtext);
printf("Server: receive msg.mtype is: %d.\n", msg.mtype);
msg.mtype = 999; // 客户端接收的消息类型
sprintf(msg.mtext, "hello, I'm server %d", getpid());
msgsnd(msqid, &msg, sizeof(msg.mtext), 0);
}
return 0;
}
msg_client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
// 用于创建一个唯一的key
#define MSG_FILE "/etc/passwd"
// 消息结构
struct msg_form {
long mtype;
char mtext[256];
};
int main()
{
int msqid;
key_t key;
struct msg_form msg;
// 获取key值
if ((key = ftok(MSG_FILE, 'z')) < 0)
{
perror("ftok error");
exit(1);
}
// 打印key值
printf("Message Queue - Client key is: %d.\n", key);
// 打开消息队列
if ((msqid = msgget(key, IPC_CREAT|0777)) == -1)
{
perror("msgget error");
exit(1);
}
// 打印消息队列ID及进程ID
printf("My msqid is: %d.\n", msqid);
printf("My pid is: %d.\n", getpid());
// 添加消息,类型为888
msg.mtype = 888;
sprintf(msg.mtext, "hello, I'm client %d", getpid());
msgsnd(msqid, &msg, sizeof(msg.mtext), 0);
// 读取类型为777的消息
msgrcv(msqid, &msg, 256, 999, 0);
printf("Client: receive msg.mtext is: %s.\n", msg.mtext);
printf("Client: receive msg.mtype is: %d.\n", msg.mtype);
return 0;
}
4.信号量
信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
5.共享内存
5.1 特点
1.共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
2.因为多个进程可以同时操作,所以需要进行同步。
3.信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。