详解linux进程间通信-消息队列
前⾔:前⾯讨论了信号、管道的进程间通信⽅式,接下来将讨论消息队列。
⼀、系统V IPC
三种系统V IPC:消息队列、信号量以及共享内存(共享存储器)之间有很多相似之处。
每个内核中的 I P C结构(消息队列、信号量或共享存储段)都⽤⼀个⾮负整数的标识符
( i d e n t i f i e r )加以引⽤。
⽆论何时创建I P C结构(调⽤m s g g e t、 s e m g e t或s h m g e t) ,都应指定⼀个关键字(k e y),关键字的数据类型由系统规定为 k e y _ t,通常在头⽂件< s y s / t y p e s . h >中被规定为长整型。关键字由
内核变换成标识符。
以上简单介绍了IPC,对接下来介绍的消息队列、信号量和共享内存有助于理解。
⼆、消息队列
1、简介
消息队列是消息的链接表 ,存放在内核中并由消息队列标识符标识。我们将称消息队列为
“队列”,其标识符为“队列 I D”。 m s g g e t⽤于创建⼀个新队列或打开⼀个现存的队列。 m s g s n d
⽤于将新消息添加到队列尾端。每个消息包含⼀个正长整型类型字段,⼀个⾮负长度以及实际
数据字节(对应于长度),所有这些都在将消息添加到队列时,传送给 m s g s n d。 m s g r c v⽤于从
队列中取消息。我们并不⼀定要以先进先出次序取消息,也可以按消息的类型字段取消息。
2、函数介绍
ftok函数
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);//“/home/linux” , 'a'
功能:⽣成⼀个key(键值)
msgget函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
功能:创建或取得⼀个消息队列对象
返回:消息队列对象的id 同⼀个key得到同⼀个对象
格式:msgget(key,flag|mode);
flag:可以是0或者IPC_CREAT(不存在就创建)
mode:同⽂件权限⼀样
进程通信方式
msgsnd函数
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:将msgp消息写⼊标识为msgid的消息队列
msgp:
struct msgbuf {
long mtype; /* message type, must be > 0 */消息的类型必须>0
char mtext[1]; /* message data */长度随意
};
msgsz:要发送的消息的⼤⼩不包括消息的类型占⽤的4个字节
msgflg:如果是0 当消息队列为满 msgsnd会阻塞
如果是IPC_NOWAIT 当消息队列为满时不阻塞⽴即返回
返回值:成功返回id 失败返回-1
msgrcv函数
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
功能:从标识符为msgid的消息队列⾥接收⼀个指定类型的消息并存储于msgp中读取后把消息从消息队列中删除msgtyp:为 0 表⽰⽆论什么类型都可以接收
msgp:存放消息的结构体
msgsz:要接收的消息的⼤⼩不包含消息类型占⽤的4字节
msgflg:如果是0 标识如果没有指定类型的消息就⼀直等待
如果是IPC_NOWAIT 则表⽰不等待
msgctl函数
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msgctl(msgid,IPC_RMID,NULL);//删除消息队列对象
程序2-2将简单演⽰消息队列:
--- snd.c ---
#include "my.h"
typedef struct{
long type;
char name[20];
int age;
}Msg;
int main()
{
key_t key = ftok("/home/liudw",'6');
printf("key:%x\n",key);
int msgid = msgget(key,IPC_CREAT|O_WRONLY|0777);
if(msgid<0)
{
perror("msgget error!");
exit(-1);
}
Msg m;
puts("please input your type name age:");
scanf("%ld%s%d",&pe,m.name,&m.age);
msgsnd(msgid,&m,sizeof(m)-pe),0);
return0;
}
--- rcv.c ---
#include "my.h"
typedef struct{
long type;
char name[20];
int age;
}Msg;
int main()
{
key_t key = ftok("/home/liudw",'6');
printf("key:%x\n",key);
int msgid = msgget(key,O_RDONLY);
if(msgid<0)
{
perror("msgget error!");
exit(-1);
}
Msg rcv;
long type;
puts("please input type you want!");
scanf("%ld",&type);
msgrcv(msgid,&rcv,sizeof(rcv)-sizeof(type),type,0);
printf("rcv--name:%s age:%d\n",rcv.name,rcv.age);
msgctl(msgid,IPC_RMID,NULL);
return0;
}
运⾏演⽰:
三、详解ftok函数
ftok根据路径名,提取⽂件信息,再根据这些⽂件信息及project ID合成key,该路径可以随便设置。
该路径是必须存在的,ftok只是根据⽂件inode在系统内的唯⼀性来取⼀个数值,和⽂件的权限⽆关。
proj_id是可以根据⾃⼰的约定,随意设置。这个数字,有的称之为project ID; 在UNIX系统上,它的取值是1到255;
为了验证以上观点,对程序2-2稍作修改,将路径和proj_id修改:
程序3-1如下:
--- snd.c ---
#include "my.h"
typedef struct{
long type;
char name[20];
int age;
}Msg;
int main()
{
key_t key = ftok("/home",'a');
printf("key:%x\n",key);
int msgid = msgget(key,IPC_CREAT|O_WRONLY|0777);
if(msgid<0)
{
perror("msgget error!");
exit(-1);
}
Msg m;
puts("please input your type name age:");
scanf("%ld%s%d",&pe,m.name,&m.age);
msgsnd(msgid,&m,sizeof(m)-pe),0);
return0;
}
--- rcv.c ---
#include "my.h"
typedef struct{
long type;
char name[20];
int age;
}Msg;
int main()
{
key_t key = ftok("/home",'a');
printf("key:%x\n",key);
int msgid = msgget(key,O_RDONLY);
if(msgid<0)
{
perror("msgget error!");
exit(-1);
}
Msg rcv;
long type;
puts("please input type you want!");
scanf("%ld",&type);
msgrcv(msgid,&rcv,sizeof(rcv)-sizeof(type),type,0);
printf("rcv--name:%s age:%d\n",rcv.name,rcv.age);
msgctl(msgid,IPC_RMID,NULL);
return0;
}
运⾏演⽰如下图:
总结:主要介绍了进程间通信的消息队列,有疑问可以留⾔,⼀定即时解答。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论