前言:前面讨论了信号、管道的进程间通讯方式,接下来将讨论消息队列。node
三种系统V IPC:消息队列、信号量以及共享内存(共享存储器)之间有不少类似之处。linux
每一个内核中的 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 >中被规定为长整型。关键字由
内核变换成标识符。
spa
以上简单介绍了IPC,对接下来介绍的消息队列、信号量和共享内存有助于理解。code
消息队列是消息的连接表 ,存放在内核中并由消息队列标识符标识。咱们将称消息队列为
“队列”,其标识符为“队列 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用于从
队列中取消息。咱们并不必定要以先进先出次序取消息,也能够按消息的类型字段取消息。
对象
#include <sys/types.h>
#include <sys/ipc.h>blog
key_t ftok(const char *pathname, int proj_id);//“/home/linux” , 'a'
功能:生成一个key(键值)队列
#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:同文件权限同样ip
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
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 则表示不等待
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",&m.type,m.name,&m.age); msgsnd(msgid,&m,sizeof(m)-sizeof(m.type),0); return 0; }
--- 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); return 0; }
运行演示:
为了验证以上观点,对程序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",&m.type,m.name,&m.age); msgsnd(msgid,&m,sizeof(m)-sizeof(m.type),0); return 0; }
--- 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); return 0; }
运行演示以下图:
总结:主要介绍了进程间通讯的消息队列,有疑问能够留言,必定即时解答。