Linux系统编程——消息队列

消息队列

1.消息队列相关概念

消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识
(1) 消息队列是进程间通信的一种方式,遵循先进先出的原则,保证了时间的顺序性。拥有该消息队列读权限的进程可以从消息队列读出数据,拥有该消息队列写权限的进程可以向消息队列发送数据
(2)消息作为节点一个一个地存放在消息队列里,可把消息队列比作信箱,消息比作依次顺序存放的信件。地址比作消息类型,内容为消息。支持双向传输,可以使用消息类型区分不同的消息。其实消息队列说白了就是用来存放消息的链表。
(3)消息队列不再局限于父子进程,在任何两个进程间都能通信。

  • 特点:
    (1)消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
    (2)消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
    (3)消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取

2.消息队列相关函数

 #include <sys/msg.h>//需要引入的头文件

(1) msgget函数(消息队列创建)

  • 作用:用来创建一个消息队列
  • 函数原型:
int msgget(key_t key, int flag);
  • 参数:
    key:某个消息队列的名字
    flag:由九个权限标志构成,它们的⽤法和创建⽂件时使⽤的mode模式标志是⼀样的

IPC_CREAT//不存在创建,存在就打开
IPC_CREAT|EXCL//不存在就创建,存在出错

  • 返回值:成功返回一个非负整数(即该消息队列的标识码),失败返回-1

(2)msgsnd函数(发送消息)

  • 作用:发送消息,即把一条消息添加到消息队列中去
  • 函数原型;
 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

  • 参数:
    msqid:由msgget函数返回的消息队列标识码,表示往哪个消息队列发数据
    msgp:是⼀个指针,指针指向准备发送的消息(即准备发送的消息的内容)
    消息的结构参考:
   struct msgbuf {
       long mtype;       /* message type, must be > 0 */
       char mtext[1];    /* message data */
   };

参数:

mtype:它必须以⼀个long int⻓整数开始,接收者函数将利⽤这个⻓整数确定消息的类型
mtext:保存消息内容的数组或指针,它必须小于系统规定的上限值

msgsz:消息的大小,即即mtext的大小。
msgflg0表示阻塞方式IPC_NOWAIT表⽰队列满不等待,返回EAGAIN错误

返回值:成功返回0,失败返回-1

(3)msgrcv函数(接收消息)

  • 作用:从一个消息队列中接收消息
  • 函数原型:
 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
  • 参数:
    msqid:由msgget函数返回的消息队列标识码,表示从哪个消息队列拿数据
    msgp:⼀个指针,指针指向准备接收的消息(即接收消息的缓冲区)
    msgsz:是msgp指向的消息⻓度,这个⻓度不含保存消息类型的那个long int⻓整型,即用sizeof()计算
    msgtyp:它可以实现接收优先级的简单形式,即接收消息的类型,即发消息结构体中的mtype
    msgflg:控制着队列中没有相应类型的消息可供接收时将要发⽣的事,即0表示阻塞方式, IPC_NOWAIT表⽰队列满不等待,返回EAGAIN错误
  • 返回值:成功返回实际放到接收缓冲区里去的字符个数,失败返回-1

(4)msgctl函数(控制消息队列)

  • 作用:消息队列的控制函数
  • 函数原型:
 int msgctl(int msqid, int cmd, struct msqid_ds *buf);

  • 参数
    msqid:由msgget函数返回的消息队列标识码
    cmd:是将要采取的动作,(有三个可取值),一般用IPC_RMID,这时候表示移除消息队列的意思

cmd的参数参考:

  1. IPC_STAT
    读取消息队列的数据结构msqid_ds,并将其存储在buf指定的地址中。
  2. IPC_SET
    设置消息队列的数据结构msqid_ds中的ipc_perm元素的值。这个值取自buf参数。
  3. IPC_RMID
    删除消息队列。

buf:一般写NULL

(5)键值生成ftok()函数

  • 作用:系统IPC键值的格式转换函数,系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
    通过ftok函数生成key值,函数ftok把一个已存在的路径名和一个整数标识符转换成一个key_t值,称为IPC键值(也称IPC key键值)。
  • 函数原型:
//所需头文件
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id)
  • 参数:
    pathname:是你指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key;
key = ftok(".", 1); //这样就是将pathname设为当前目录。可随便设置

proj_id:子序号。虽然是int类型,但是只使用8bits(1-255)。

消息队列示例

msgSnd.c 文件

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct msgbuf{
       long mtype;       /* message type, must be > 0 */
       char mtext[128];    /* message data */
};

int main()
{

    key_t key;
    int msgid;
    int sendret;
    int rcvret;
    struct msgbuf sendMsg = {897,"hello thi is from que"};
    struct msgbuf rcvBuf;
    key = ftok(".", 1); //创建key值对
    if(key == -1)
    {
        printf("faild to get the key\n");
    }
    printf("the key is:%x\n",key);
    msgid = msgget(key,IPC_CREAT|0777);//创建消息队列,并赋予可读可写可执行权限
    if(msgid < 0){
        printf("creat que faild\n");
    }
    sendret = msgsnd(msgid,&sendMsg,strlen(sendMsg.mtext),0);//向消息队列发送消息
    if(sendret < 0){
        printf("send msg fail\n");
    }else{

        printf("send successfully the msg is %s \n",sendMsg.mtext);
    }
    rcvret = msgrcv(msgid,&rcvBuf,sizeof(rcvBuf.mtext),888,0);//接受队列中type为888的消息
    if(rcvret < 0){
        printf("recevive msg fail\n");
    }else{
        printf("get %d bytes : %s\n",rcvret,rcvBuf.mtext);
    }
    msgctl(msgid,IPC_RMID,NULL);//关闭消息队列



    return 0;
}

msgRcv.c 文件

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct msgbuf{
       long mtype;       /* message type, must be > 0 */
       char mtext[128];    /* message data */
};

int main()
{

    key_t key;
    int msgid;
    int sendret;
    int rcvret;
    struct msgbuf sendMsg = {888,"hello ,get over thank you"};
    struct msgbuf rcvBuf;
    key = ftok(".", 1); //创建key值对
    if(key == -1)
    {
        printf("faild to get the key\n");
    }
    printf("the key is:%x\n",key);
    msgid = msgget(key,IPC_CREAT|0777);//创建消息队列,并赋予可读可写可执行权限
    if(msgid < 0){
        printf("creat que faild\n");
    }

    rcvret = msgrcv(msgid,&rcvBuf,sizeof(rcvBuf.mtext),897,0);//接受队列中type为897的消息
    if(rcvret < 0){
        printf("recevive msg fail\n");
    }else{
        printf("get %d bytes : %s\n",rcvret,rcvBuf.mtext);
    }
    sendret = msgsnd(msgid,&sendMsg,strlen(sendMsg.mtext),0);//向消息队列发送消息
    if(sendret < 0){
        printf("send msg fail\n");
    }else{

        printf("send successfully ,Send msg is %s \n",sendMsg.mtext);
    }
    msgctl(msgid,IPC_RMID,NULL);//关闭消息队列



    return 0;
}

运行结果
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值