进程间通信之消息队列

一、什么是消息队列
    消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。每个数据块都被认为含有一个类型,接受进程可以独立接受含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步阻塞问题,但是消息队列与命名管道一样,每个数据块都有最大长度的限制。

Linux用宏MSGMAX和MSGMNB来限制一条消息的最大长度和一个队列的最大长度。
二、消息队列中的函数

1、msgget函数:该函数用来创建一条消息队列
    int magget(key_t ,key,int msgflg);

    程序必须提供一个键来命名某个特定的消息队列。msgflg是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。msgflg可以与IPC_CREAT做与操作,表示当key所命名的消息队列不存在时创建一个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被忽略而只返回一个标识符。
2、msgsnd函数:用来把消息添加到消息队列中

    int msgsnd(int msgid,const void *msg_ptr,size_t msg_sz,int msgflg);
    msgid是由msgget函数返回的消息队列标识符,msg_ptr是一个指向准备发送消息的指针,但是消息的数据结构却有一定的需求,指针msg_ptr所指向的消息结构一定是以一个长整型的成员变量开始的结构体,接受函数将用这个成员确定这个消息的类型。

struct my_message
{
    long int msg_type;
};

msg_sz是msg_ptr所指向的消息的长度,而不是整个结构体的长度。msgflg用于控制当前消息队列满或消息队列到达系统范围的限制时要发生的事情。
如果调用成功,消息数据的一副本被放到消息队列中并返回0,失败时返回-1.

3、msgrcv函数;用来从一个消息队列中获取消息
    int msgrcv(int msgid,const void *msg_ptr,size_t msg_sz,long int msg_type,int msgflg);

    msgid, msg_ptr,msg_sz的作用和函数msgsnd函数中的参数相同。
    msg_type可以实现一种简单的接受优先级。如果msg_type为0,就获取队列中的第一个消息。如果它的值大于0,将获取到相同类型的第一个信息,如果它小于0,就获取类型等于或小于mag_type的绝对值的第一个消息。

调用成功时,该函数返回放到接受缓冲区中的字节数,消息被复制到由msg_ptr所指向的用户分配的缓冲区中,然后删除消息队列中对应的消息,失败时返回-1.
4、msgctl函数:该函数用来控制消息队列,它与共享内存中的shmctl函数相似。

int msgctl(int msgid,int command,struct msgid_ds *buf);
command是将要采取的动作,它可以取三个值。

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;
    uid_t shm_prem.mode;

};

成功返回0,失败返回-1.
三、例子:

msg_server.c

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/msg.h>
#include<stdlib.h>
#include<errno.h>
struct msg_st
{
        long int msg_type;
        char text[BUFSIZ];
};
int main()
{
        int running = 1;
        int msgid = -1;
        struct msg_st data;
        long int msgtype = 0;
        msgid = msgget((key_t)1234,0666 | IPC_CREAT);
        if (msgid == -1)
        {
                fprintf(stderr,"msgget failed with error: %d\n",errno);
                exit(EXIT_FAILURE);
        }
        while (running)
        {
                if (msgrcv(msgid,(void*)&data,BUFSIZ,msgtype,0) == -1)
                {
                        fprintf(stderr,"msgrcv failed with errno: %d\n",errno);
                        exit(EXIT_FAILURE);
                }
                printf("You wrote: %s\n",data.text);
                if (strncmp(data.text,"end",3) == 0)
                        running = 0;
        }
        if (msgctl(msgid,IPC_RMID,0) == -1)
        {
                fprintf(stderr,"msgctl(IPC_RMID) failed\n");
                exit(EXIT_FAILURE);
        }
        exit(EXIT_SUCCESS);
}


msg_client.c

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

         }
        while (running)
        {
                printf("Enter some text: ");
                fgets(buffer,BUFSIZ,stdin);
                data.msg_type = 1;
                strcpy(data.text,buffer);
                if (msgsnd(msgid,(void*)&data,MAX_TEXT,0) == -1)
                {
                        fprintf(stderr,"msgsnd failed\n");
                        exit(EXIT_FAILURE);
                }
                if (strncmp(buffer,"end",3) == 0)
                        running = 0;
                sleep(1);
        }
        exit(EXIT_SUCCESS);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值