linux 消息队列

分类: 计算机基础 , c++ , linux

2020-10-21

|

98

|

评论:0

分享:

消息队列是消息的链表,存放在内核中并由消息队列标识符标识.消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等特点.消息队列是UNIX下不同进程之间可实现共享资源的一种机制,UNIX允许不同进程将格式化的数据流以消息队列形式发送给任意进程.对消息队列具有操作权限的进程都可以使用msget完成对消息队列的操作控制.通过使用消息类型,进程可以按任何顺序读信息,或为消息安排优先级顺序.

c語言中相關API


msgget()函数

int msgget(key_t key, int msgflg);

该函数用来创建和访问一个消息队列。

与其他的IPC机制一样,程序必须提供一个键来命名某个特定的消息队列。msgflg是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。msgflg可以与IPC_CREAT做或操作,表示当key所命名的消息队列不存在时创建一个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被忽略,而只返回一个标识符。

它返回一个以key命名的消息队列的标识符(非零整数),失败时返回-1.


msgsnd()函数

int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);

msgid是由msgget函数返回的消息队列标识符。

msg_ptr是一个指向准备发送消息的指针,但是消息的数据结构却有一定的要求,指针msg_ptr所指向的消息结构一定要是以一个长整型成员变量开始的结构体,接收函数

将用这个成员来确定消息的类型。所以消息结构要定义成这样: 

struct my_message {
    long int message_type;
    /* The data you wish to transfer */
};

msg_sz 是msg_ptr指向的消息的长度,注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度。

msgflg 用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情。

如果调用成功,消息数据的一分副本将被放到消息队列中,并返回0,失败时返回-1.


msgrcv()函数

int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);

该函数用来从一个消息队列获取消息。

msgid, msg_ptr, msg_st 的作用也函数msgsnd()函数的一样。

msgtype 可以实现一种简单的接收优先级。如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息。

msgflg 用于控制当队列中没有相应类型的消息可以接收时将发生的事情。为【IPC_NOWAIT】时,如果消息队列中不存在指定的msgtype的消息时不会阻塞,而是立即返回。返回值为【ENOMSG】。

调用成功时,该函数返回放到接收缓存区中的字节数,消息被复制到由msg_ptr指向的用户分配的缓存区中,然后删除消息队列中的对应消息。失败时返回-1。


msgctl()函数

int msgctl(int msgid, int command, struct msgid_ds *buf);

该函数用来控制消息队列。

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

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

buf是指向msgid_ds结构的指针,它指向消息队列模式和访问权限的结构。msgid_ds结构至少包括以下成员: 

struct msgid_ds
{
    uid_t shm_perm.uid;
    uid_t shm_perm.gid;
    mode_t shm_perm.mode;
};

成功时返回0,失败时返回-1.


//20201021 学习linux消息队列记录,相关代码未经验证。

//20201026 代码验证通过,并更新部分细节。

文章來源:https://www.cnblogs.com/52php/p/5862114.html

验证代码如下:

msg_recv.c

#include <stdio.h>
#include <sys/msg.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
struct msg_st
{
    /* data */
    long int msg_type;
    char text[BUFSIZ];
};
int main(void)
{
    // init val
    int msgid = -1;
    long int msg_type = 2;
    struct msg_st data;
    key_t key = 1234;
    msgid = msgget(key, 0666 | IPC_CREAT);

    // if not get a msg id, exit
    if (msgid == -1)
    {
        fprintf(stderr, "msgget failed width error: %d\n", errno);
        exit(EXIT_FAILURE);
    }

    // waiting for msg
    int recv_flag = 0;
    int chec_msg_flag = 0;
    while (1)
    {
        // try recv msg, if wrong, exit
        recv_flag = msgrcv(msgid, (void *)&data, BUFSIZ, msg_type, IPC_NOWAIT);
        if (recv_flag == -1 || recv_flag == ENOMSG)
        {
            if (chec_msg_flag > 10)
            {
                fprintf(stderr, "msgrcv failed width erro: %d\n", errno);
                chec_msg_flag = 0;
            }
            else
            {
                chec_msg_flag++;
            }
        }
        else
        {
            // print msg
            printf("You wrote: %s\n", data.text);

            // if get end msg, stop
            if (strncmp(data.text, "end", 3) == 0)
            {
                break;
            }
        }
        sleep(1);
    }

    // try delete msg
    if (msgctl(msgid, IPC_RMID, 0) == -1)
    {
        fprintf(stderr, "msgctl(IPC_RMID) failed\n");
    }

    // app stop and exit
    printf("stop recev!");
    exit(EXIT_SUCCESS);
}

msg_send.c

#include <stdio.h>
#include <sys/msg.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_TEXT 512
struct msg_st
{
    /* data */
    long int msg_type;
    char text[BUFSIZ];
};
int main(void)
{
    struct msg_st data;
    char buffer[BUFSIZ];
    int msgid = -1;
    key_t key = 1234;
    // build msg queue
    msgid = msgget(key, 0666 | IPC_CREAT);
    if (msgid == -1)
    {
        fprintf(stderr, "msgget failed error: %d\n", errno);
        exit(EXIT_FAILURE);
    }

    // send msg to queue, until send end msg.
    while (1)
    {
        // wait user input msg
        printf("Enter some text: \n");
        fgets(buffer, BUFSIZ, stdin);
        data.msg_type = 2;
        strcpy(data.text, buffer);

        // send msg
        if (msgsnd(msgid, (void *)&data, MAX_TEXT, 0) == -1)
        {
            fprintf(stderr, "msgsnd failed\n");
            exit(EXIT_FAILURE);
        }

        // break went input is end
        if (strncmp(buffer, "end", 3) == 0)
        {
            break;
        }
        sleep(1);
    }  
    
}

Powered by Froala Editor



转载请注明来源

文章:linux 消息队列

链接:/article/14

作者:大猫

本文共 0 个回复

发表评论 (对文章评论)

captcha