一,本质
内核中提供的链表
二.特性
1)消息队列提供了一个从一个进程向另外一个进程发送一块数据的方式(可用于任何进程之间)
2)每个数据块都被认为是有一个类型,接受者进程接受的数据块可以有不同的类型值5)
3)双向通信,全双工
4)面向数据报
5)内置了同步互斥机制
6)生命周期随内核(会一直存在,直到显式删除或者系统重启)
7)限制:每个消息的最大长度有限,每个消息队列的总的字节数也是有上限的,系统上消息队列的总的个数也是有限的。
三.工作方式
AB代表两个进程,从哪个通道发送就从哪个通道接收,发送了没接收就堵塞在通道中,接收方什么时候打开什么时候接收。
四.API
1)创建和访问一个消息队列
a)头文件:#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
b)函数原型:int msgget(key_t key, int msgflg);
c)函数参数:key 消息队列的名字 msgget 由九个权限标志构成,用法和创建文件的mode一样(打开0,创建IPC_CREAT|0644)
d)返回值:成功返回非负整数,即消息队列的标识码,失败返回-1
e)栗子
7 int main(void){
8 int key;
9 key_t msg=001;
10 key=msgget(msg,IPC_CREAT|0644);
11 if(key==-1) perror("msgget"),exit(1);
12 return 0;
13 }
2)删除消息队列
a)头文件:和msgget一样
b)函数原型: int msgctl(int msqid, int cmd, struct msqid_ds *buf);
c)参数:msqid 是msgget返回的消息队列的标识码 第三个参数删除时不关注写0
cmd有三个可取值:IPC_STAT把结构体msqid_ds中的数据设置为消息队列的当前关联值
IPC_SET在进程有足够权限的前提下,把消息队列的关联值设置为msqid_ds结构体给出的值
IPC_RMID删除消息队列
d)返回值:成功返回0,失败返回-1
3)将一条消息添加到消息队列中
a)头文件:和msgget一样
b)函数原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
c)参数:msqid 是msgget返回的消息队列的标识码 msgp 是一个指针,指针指向准备发送的信息
msgsz:是msgp指向的消息的长度,长度不包含保存消息类型的longint的大小
msgflg:控制当前消息队列满或者达到系统上限时将要发生的事(IPC_NOWAIT表示队列满不等待,返回EAGAIN错误)(一般写0)
d)返回值:成功返回0,失败返回-1
e)发送消息的结构有两点制约:小于系统规定的上限值,必须以一个long int长整数开始
通常发送一个结构体 struct msgbuf{long channel,char mtext[1024]};
4)接收消息队列中的消息
a)头文件:和msgget一样
b)函数原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
c)参数:msqid 是msgget返回的消息队列的标识码 ,msgp 是一个指针,指针指向准备发送的信息
msgsz:是msgp指向的消息的长度,长度不包含保存消息类型的longint的大小
msgtype:可以实现接收优先级的简单形式(为0返回队列的第一条消息,大于0返回队列第一条类型等于msgtype的消息,小于0返回队列第一条类型小于等于msgtype绝对值的消息,并且满足条件的消息类型最小的消息)
msgflag:控制着队列中没有相应类型的消息可供接受时将要发生的事(为IPC_NOWAIT,队列没有可读消息不等待,返回ENOMSG错误,为MSG_NOERROR,消息大小超过msgsz时被截断)
msgtype>0且msgflg=MSG_EXCEPT,接收类型不等于msgtype的第一条消息
d)返回值:成功返回放入接收缓冲区里的字符个数,失败返回-1
插播一段代码
comm.h
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4 #include <sys/ipc.h>
5 #include <sys/msg.h>
6 struct msgbuf{
7 long mtype; //几号通道
8 char text[1024];
9 };
10
11 #define SEVER 1
12 #define CLIENT 2
13
14 #define PATHNAME "."
15 #define ID 0x001
16
17 int CreateMsg(int flags);
18 int Sendmsg(int msgid,char * msg,int channel);
19 int Recmsg(int msgid,int channel,char * out);
20 int Destorymsg(int msgid);
comm.c
1 #include "comm.h"
2
3 int CreateMsg(int flags){
4 key_t key=ftok(PATHNAME,ID);
5 if(key<0){
6 perror("ftok");
7 return 1;
8 }
9
10 int msggid;
11 if(flags==0){
12 msggid=msgget(key,IPC_CREAT|0644);
13 }else if(flags==1){
14 msggid=msgget(key,0);
15 }
16 if(msggid<0){
17 perror("msggid");
18 return 1;
19 }
20
21 return msggid;
22 }
23
24 int Destorymsg(int msgid){
25 int del=msgctl(msgid,IPC_RMID,0);
26
27 if(del<0){
28 perror("msgctl");
29 return -1;
30 }
31 return 0;
32 }
33
34 int Sendmsg(int msgid,char * msg,int channel){
35 struct msgbuf buf;
36 buf.mtype=channel;
37 strcpy(buf.text,msg);
38
39 int sen=msgsnd(msgid,&buf,strlen(buf.text),0);
40 if(sen<0){
41 perror("msgsnd");
42 return -1;
43 }
44 return 0;
45 }
46
47 int Recmsg(int msgid,int channel,char * out){
48 struct msgbuf buf;
49 buf.mtype=channel;
50 memset(buf.text,0x00,sizeof(buf.text));
51
52 int rec=msgrcv(msgid,&buf,sizeof(buf.text),channel,0);
53 if(rec<0){
54 perror("msgrcv");
55 return -1;
56 }
57 strcpy(out,buf.text);
58 return 0;
59 }
client.c
1 #include "comm.h"
2
3 int main(void){
4 int msgid=CreateMsg(1);
5
6 char buf[1024]={0};
7
8 while(1){
9 printf("Client say#");
10 fflush(stdout);
11 int ret=read(0,buf,sizeof(buf));
12 if(ret<=0) break;
13 else
14 buf[ret-1]=0;
15
16 Sendmsg(msgid,buf,CLIENT);
17 memset(buf,0x00,sizeof(buf));
18
19 Recmsg(msgid,SEVER,buf);
20 printf("Sever say#%s\n",buf);
21
22 }
23 return 0;
24 }
sever.c
1 #include "comm.h"
2
3 int main(void){
4 int msgid=CreateMsg(0); //create
5
6 int ret;
7 char buf[1024];
8 while(1){
9 Recmsg(msgid,CLIENT,buf);
10 printf("Client say#:%s\n",buf);
11
12 memset(buf,0x00,sizeof(buf));
13 printf("Seversay#");
14 fflush(stdout);
15 ret=read(0,buf,sizeof(buf));
16 if(ret<=0)
17 break;
18 else
19 buf[ret-1]=0;
20 if(strncmp(buf,"exit",4)==0)
21 break;
22 Sendmsg(msgid,buf,SEVER);
23 }
24 Destorymsg(msgid);
25 return 0;
26 }
Makefile
2 .PHONY:all
3 all:client sever
4
5 client:client.c comm.c
6 gcc -o $@ $^
7
8 sever:sever.c comm.c
9 gcc -o $@ $^
10
11 .PHONY:clean
12
13 clean:
14 rm -f client sever
用消息队列实现了客户端和服务器间简单的消息传送
在写代码中遇到的问题:Makefile中由于vimrc中设置了set expandtab 总是报三号错误,改成set noexpandtab 就好啦!