System V IPC:消息队列

概念

  • 底层是一个链队列
  • 与共享内存的不同是:内核要保证消息队列的FIFO性质,因此当有多个接收方进程接收消息队列中的消息的时候,不会产生冲突,由内核来协调他们的执行顺序。由于队列性质,队尾写,队头读,所以读写也不会存在冲突。

API和涉及的数据结构

创建消息队列
#include <sys/msg.h>
int msgget(key_t key,int flag);

参数和返回值类比共享内存shmget

发送消息
#include <sys/msg.h>
int msgsnd(int msqid,void * ptr,size_t nbytes,int flag);

参数表:
msqid:消息队列ID
ptr:指向待发送的消息的指针
nbytes:消息的大小
flag:当消息队列满时如何处理(IPC_NOWAIT?)
返回值:
0:成功
-1:失败

  • 消息结构体:
    msgsnd结构体中的ptr指向要发送的信息,此信息是一个结构体,需要用户自己定义,但是必须包含消息类型和消息的内容,例如下
struct mymsg
{
  long msgtype;
  char msgtext[MAXLENTH];
}
接收信息
#include <sys/msg.h>
int msgrcv(int msqid,void * ptr,size_t nbytes,long type,int flag);

参数表:
msqid:消息队列ID
ptr:指向待发送的消息的指针
nbytes:消息的大小
type:消息类型
flag:当消息队列满时如何处理(NOWAIT?)
返回值:
大于0:消息中数据部分的长度
-1:失败

  • 消息类型的用法

type = 0时,返回队列中的第一个消息
type > 0时,返回队列中消息类型为type的第一个消息
type < 0时,返回消息队列中类型值小于或等于type的消息,若有多个,则返回最小的

注意数据大小要满足:消息队列定义的消息信息大小>=msgrcv中的数据大小>=msgsnd中的数据大小(即MAXLENTH>=msgrcv中nbytes>=msgsnd中的nbytes

消息队列操作
#include <sys/msg.h>
int msg(int msqid,int cmd,struct msqid_ds * buf);

参数表:
msqid:消息队列ID
cmd:待执行的操作
buf:存放消息队列属性的内存地址
返回值:
0:成功
-1:失败

示例代码

写端:创建消息队列,发送消息

#include <sys/msg.h>
#include <iostream>
#include <unistd.h>
#include <cstring>
#include <sys/ipc.h>
using namespace std;

#define MAXLENTH 128

struct msg_st
{
    int msg_type;
    char msg_text[MAXLENTH];
};

int main()
{

    int msg_id;
    int key = ftok(".",512);
    char buf[10];

    struct msg_st sndMsg;
    sndMsg.msg_type = 1;

    msg_id = msgget(key,IPC_CREAT|0666);
    if(msg_id == -1)
    {
        perror("msgget");
        exit(EXIT_FAILURE);
    }

    cin >> buf;
    strcpy(sndMsg.msg_text,buf);

    if(msgsnd(msg_id,(void *)&sndMsg,10,0)==-1)
    {
        perror("msgsnd");
        exit(EXIT_FAILURE);
    }
    sleep(10);
    return 0;
}

读端:接收信息,删除消息队列

#include <sys/msg.h>
#include <iostream>
#include <sys/ipc.h>
#include <cstring>
using namespace std;

#define MAXLENTH 128

struct msg_st
{
    int msg_type;
    char msg_text[MAXLENTH];
};

int main()
{

    int msg_id;
    int key = ftok(".",512);
    char buf[100];

    struct msg_st rcvMsg;

    msg_id = msgget(key,0666);
    if(msg_id == -1)
    {
        perror("msgget");
        exit(EXIT_FAILURE);
    }

    if(msgrcv(msg_id,(void *)&rcvMsg,20,0,0)==-1)
    {
        perror("msgrcv");
        exit(EXIT_FAILURE);
    }
    cout <<rcvMsg.msg_text <<endl;
    msgctl(msg_id,IPC_RMID,0);
    return 0;
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • width: 65%;border: 1px solid #ddd;outline: 1300px solid #...
    邵胜奥阅读 4,885评论 0 1
  • 两种方式:1. 管道 2. 消息队列 管道 就像现实中的水管,水就像数据 管道是一种半双工的通信方式 数据只能单向...
    Yojiaku阅读 167评论 0 0
  • { "Unterminated string literal.": "未终止的字符串文本。", "Identifi...
    栗子雨阅读 7,965评论 0 3
  • 光阴似箭,日月如梭。转眼间二十年过去了,我已经是一名科学家了。已经很长时间没有回家了。 ...
    李雅康阅读 757评论 0 0
  • 今天早上乘坐地铁,因为正值上班高峰,人特别多,我好不容易挤上去,赶紧抓住扶手。就在我握扶手的一霎那,一位午轻漂亮的...
    蓝天白云215阅读 222评论 3 10