消息队列特性

  1. 消息队列存在于Linux内核中,可以使数据双向流动
  2. 数据在内核中,即使进程结束数据依然存在
  3. 消息队列实际上是消息链表,每个队列都有自己的标识符

消息队列API

  1. msgget——创建一个消息队列
  2. msgsnd、msgrcv——添加数据到消息队列、从消息队列获取数据
  3. msgctl——控制消息队列

一、msgget——创建一个消息队列

1.原函数

表头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
定义函数
int msgget(key_t key, int msgflg);

函数说明——创建和访问一个消息队列
key——消息队列的名称(使用ftok()函数获取)
msgflg——消息队列的访问权限
返回值——成功返回此消息队列的标识符(非零整数)。失败时返回-1,失败原因在errno中

2.示例

key_t key;
key = ftok(".",'z');

int msgId = msgget(key,IPC_CREAT|0777);//创建和访问一个消息队列

二、msgsnd、msgrcv——添加数据到消息队列、从消息队列获取数据

1.原函数

表头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
定义函数
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

函数说明——msgsnd()添加数据到消息队列、msgrcv()从消息队列获取数据
msqid —— 由msgget()返回的队列标识符
msgp —— 需要存放/读取的结构体
msgsz —— 需要存放/读取的大小
msgtyp —— 读取消息队列的位置
msgflg —— 默认值为0
返回值——成功msgsnd()返回0,msgrcv()返回实际复制到mtext数组中的字节数。错误两个函数都返回-1,errno表示错误

2.参数取值
msgp默认结构体如下:

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

3.示例

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

struct msgbuf sendBuf = {988,"thank your welcome\n"};
struct msgbuf readBuf;

msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),888,0);//从消息队列获取数据
msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);//添加数据到消息队列

三、msgctl——控制消息队列

1.原函数

表头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
定义函数
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

函数说明—— 控制消息队列,它与共享内存的shmctl函数相似
msqid —— 由msgget()返回的队列标识符
cmd —— 控制msqid_ds结构体指令
buf —— 记录消息队列的信息(消息队列模式和访问权限)(默认为NULL)
返回值——成功时返回0。失败时返回-1,errno表示错误

2.参数取值
command是将要采取的动作,它可以取3个值,

IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。
IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值
IPC_RMID:删除消息队列

msqid_ds默认结构体如下:

struct msqid_ds {
           struct ipc_perm msg_perm;     /* Ownership and permissions */
           time_t          msg_stime;    /* Time of last msgsnd(2) */
           time_t          msg_rtime;    /* Time of last msgrcv(2) */
           time_t          msg_ctime;    /* Time of last change */
           unsigned long   __msg_cbytes; /* Current number of bytes in
                                            queue (nonstandard) */
           msgqnum_t       msg_qnum;     /* Current number of messages
                                            in queue */
           msglen_t        msg_qbytes;   /* Maximum number of bytes
                                            allowed in queue */
           pid_t           msg_lspid;    /* PID of last msgsnd(2) */
           pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
       };

3.示例

msgctl(msgid,IPC_RMID,NULL);//删除消息队列

消息队列通信例程

程序1

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

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

int main()
{
        struct msgbuf sndbuf={889,"Hello"};
        struct msgbuf rcvbuf;
        key_t key;
        int msgid;

        key=ftok(".",'k');//键值获取

        msgid=msgget(key,IPC_CREAT|0777);//创建一个消息队列 

        msgsnd(msgid,&sndbuf,sizeof(sndbuf.mtext),0);//添加数据到消息队列 

        msgrcv(msgid,&rcvbuf,sizeof(rcvbuf.mtext),888,0);//从消息队列获取数据

        printf("rcvbuf.mtype=%ld,rcvbuf.mtext=%s\n",rcvbuf.mtype,rcvbuf.mtext);

        msgctl(msgid,IPC_RMID,NULL);//删除消息队列

        return 0;
}

程序2

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

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

int main()
{
        struct msgbuf sndbuf={888,"World"};
        struct msgbuf rcvbuf;
        key_t key;
        int msgid;

        key=ftok(".",'k');//键值获取

        msgid=msgget(key,IPC_CREAT|0777);//访问一个消息队列 

        msgrcv(msgid,&rcvbuf,sizeof(rcvbuf.mtext),889,0);//从消息队列获取数据

        printf("rcvbuf.mtype=%ld,rcvbuf.mtext=%s\n",rcvbuf.mtype,rcvbuf.mtext);

        msgsnd(msgid,&sndbuf,sizeof(sndbuf.mtext),0);//添加数据到消息队列 


        msgctl(msgid,IPC_RMID,NULL);//删除消息队列

        return 0;
}

运行结果:打开任意程序后消息队列阻塞,等待另外一个程序将所需数据录入,开启另外一程序后两程序达到消息通信的目的。
rcvbuf.mtype=889,rcvbuf.mtext=Hello
rcvbuf.mtype=888,rcvbuf.mtext=World

星辰~念