第19课-消息队列编程

19.1 基本概念

消息队列就是一个消息的链表。而一条消息则可看作一个记录,具有特定的格式。进程可以向中按照一定的规进程可以向中按照一定的规则添加新消息;另一些进程则可以从消息队列中读走消息。

消息队列可以看成进程间通讯的方式,即IPC,和前面的共享内存作用类似。

19.2 函数学习

1. 创建/打开消息队列

(1)函数名

msgget()

(2)函数原型

int msgget(key_t key, int msgflg);

(3)函数功能

get a message queue identifier

(4)所包含头文件

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

(5)返回值

成功:消息队列的id

失败:-1

(6)参数说明

key:键值

msgflg:打开标志,IPC_CREAT:表明新创建一个消息队列;IPC_EXCL,表示已经存在。

 

2. 读消息

(1)函数名

msgrcv()

(2)函数原型

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

(3)函数功能

从消息队列中接收消息(mseeage operations)。

(4)所包含头文件

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

(5)返回值

成功:实际接收到的数据长度

失败:-1

(6)参数说明

msqid:消息队列的指针。

msgp:存放取出的消息。

msgsz:希望取到消息的最大长度。

msgtyp:消息的类型。0:忽略类型,直接取消息队列中的第一条消;>0;取消息队列中类型等于msgtyp的第一条消息;<0:取类型比msgtyp的绝对值要小或者等于的消息。如果有多条消息满足该条件,就取类型最小的一条。

msgflg:标志

 

3. 写消息

我们首先看一个概念:消息结构。消息结构一般是自定义的,但是它的结构确实相对固定的。

struct msgbuf
{
long mtype;     /*message type, must be > 0*/
char mtex[1];     /*message data*/
}

 

(1)函数名

msgsnd()

(2)函数原型

int msgnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

(3)函数功能

发送消息到消息队列(mseeage operations)。

(4)所包含头文件

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

(5)返回值

成功:0

失败:-1

(6)参数说明

msqid:消息队列的id;

msgp:指向要发送的消息;

msgsz:消息的长度,和消息结构的定义方式类似,但是省去了long mtype;项。

msgflg:标志

 

4. 设置(删除)消息队列

(1)函数名

msgctl()

(2)函数原型

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

(3)函数功能

控制消息队列(message control operations)

(4)所包含头文件      

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

(5)返回值

成功:0

失败:-1

(6)参数说明

msqid:消息队列的id;

cmd:对消息队列执行的操作,IPC_RMID表示删除;

buf:获取内核中的msqid_ds结构,一般不用。

 

19.3 综合实例

消息队列通讯

程序说明:本例中我们有两个进程:进程A和进程B。进程A的作用是读取键盘上输入的字符串,A进程把它们构建成一个消息,在把这个消息放入消息队列中。B进程负责从消息队列中读取消息,并且把消息打印出来。

A进程:(1)创建消息队列;(2)while循环,获取键盘的输入(包括消息类型和消息数据),发送到消息队列;(3)删除消息队列。

send.c

#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdio.h>
struct msgt
{
         long msgtype;
         char msqtext[1024];
};                  /*分号必须有*/
int main()
{
         int msqid;
         int msg_type;
         char str[256];
         struct msgt msgs;
         //1.创建消息队列
         msqid = msgget(1024, IPC_CREAT);
         //2.循环
         while(1)
         {
                   printf("please input message type, 0 for quit!\n");
                   scanf("%d",&msg_type);
                   //获取消息类型
                   //如果用户输入的消息类型是0,退出该循环
                   if(msg_type == 0)
                            break;
                   //获取消息数据
                   printf("please input content!\n");
                   scanf("%s",str);
                   msgs.msgtype = msg_type;
                   strcpy(msgs.msqtext,str);
                   //发送消息
                   msgsnd(msqid, &msgs, sizeof(struct msgt), 0);
        
         }
         //3.删除消息队列
         msgctl(msqid, IPC_RMID, 0);
         return 0;
}

 

进程B说明:(1)打开消息队列;(2)接收消息队列中的消息;(3)打印消息队列中的数据。我们融入多进程的方式,将(2)(3)放在子进程中,以提高效率。

receive.c

#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdio.h>
int msqid = 0;
struct msgt
{
         long msgtype;
         char msqtext[1024];
};
void childprocess()
{
         struct msgt msgs;
         //接收消息队列
         while(1)
         {
                   msgrcv(msqid, &msgs, sizeof(struct msgt), 0, 0);
                   /*0表示消息队列中的第一条消息,一旦取出了一次的消息就不再存在*/
                   //打印消息队列中的数据
                   printf("msg text:%s\n",msgs.msqtext);
         }
         return;
 
}
void main()
{
         int i;
         int cpid;
         //1.打开消息队列
         msqid = msgget(1024, IPC_EXCL);
         //2.创建3个子进程
         for(i=1;1<3;i++)
         {
                   cpid = fork();
                   if(cpid<0)
                            printf("creat choldprocess error!\n");
                   else if(cpid == 0)
                            childprocess();
         }
}

 

运行结果:在同样的两个终端中的程序可以相互通讯。