Linux进程通信之消息队列

目录

1、消息队列介绍

1.1、缺点

1.2、优点

2、函数接口介绍

2.1、msgget

2.2、msgsnd

2.3、msgrcv

2.4、msgctl

3、实操


1、消息队列介绍

        消息队列与管道类似,但不需要像管道一样要提前创建管道文件,不使用文件方式打开、关闭,而转用函数接口在使用时再创建。多个进程可以通过相同的键值获取到同一消息队列的描述符,从而访问消息队列,进行通信。

1.1、缺点

        与管道一样,若发送方持续发送消息,而接收方一直未接收消息,待消息队列满时,发送方会发送失败。

        Linux系统有两个宏定义MSGMAXMSGMNB,以字节为单位分别定义了一条消息的最大长度一个队列的最大长度

1.2、优点

        1、提供了从一个进程向另一进程发送数据块的方法,数据块可以被标记为不同类型的消息。接收消息进程可根据消息类型独立接收每条消息,可实现消息分类简单的优先级控制

        2、可通过设置非等待标志,使发送消息与接收消息失败时不阻塞。

2、函数接口介绍

2.1、msgget

        用于创建一个消息队列,或获取一个已有的消息队列的描述符。成功返回队列描述符,失败返回-1。其他函数接口通过消息队列描述符,对指定消息队列进行操作。

函数原型:

int msgget(key_t key, int msgflg);

        1、key:用来命名某个特定的消息队列。多个进程可以通过相同的键值获取到同一队列的描述符

        2、msgflg:包括由9bit权限标志,设置本进程所属用户的进程、用户同属组的进程与其他进程对该消息队列的访问权限。与一个特殊位IPC_CREAT按位或,来创建一个新的消息队列。若用key命名的消息队列已存在,操作不出错,IPC_CREAT被忽略。

2.2、msgsnd

        用于把消息添加到消息队列中。成功返回0,失败返回-1。消息以结构体形式保存。

函数原型:

int msgsnd(int msqid, const void *msg_ptr, 
    size_t msg_sz, int msgflg);

        1、msqid:msgget()返回的消息队列标识符。

        2、msg_ptr:指向待发送消息的指针。消息结构体形式:

struct my_massage{
    long int message_type;
    ......
}

        消息结构体必须以 长整型message_type 开始,其指定了消息的类型。后续为实际消息内容,可以以数组等形式保存。

        3、msg_sz:消息内容的字节长度,不包括长整型消息类型。

        4、msgflg:控制当消息队列满或一条消息过长时函数的动作。

        若msgflg设置为IPC_NOWAIT,当消息队列已满时,函数不发送消息,立即返回,返回-1;若IPC_WAIT标志被清除,则函数阻塞,等待到直到消息队列有空间后,将消息发送出去。

        消息长度超出最大消息长度时的可能结果:消息被截断、消息被分片 依次发送、消息发送失败。

2.3、msgrcv

        用于从消息队列获取一条消息。成功返回消息内容长度字节数,并将信息拷贝到msg_ptr指向的结构体中,删除消息队列中对应的消息;失败返回-1。

函数原型:

int msgrcv(int msqid, void *msg_ptr, 
    size_t msg_sz, long int msgtype, 
    int msgflg);

        1、msqid:消息队列描述符。

        2、msg_ptr:接收方拥有的消息结构体,用于接收来自消息队列的消息的拷贝。

        3、msg_sz:一次能接收的消息内容的最大长度。

        4、msgtype:指定要接收的消息类型,可实现简单的优先级控制。

        (1)0:接收消息队列的第一条消息。

        (2)n:只接收类型为n的消息。

        (3)-n:接收消息类型 <= n 的所有消息。

        5、msgflg:设置阻塞或非阻塞(IPC_NOWAIT)。

2.4、msgctl

        用于设置或获取进程对消息队列的权限信息,或删除消息队列。成功返回0,失败返回-1。若消息队列被删除,则正对该消息队列进行的读、写会失败。

函数原型:

int msgctl(int msqid, int command, 
    struct msqid_ds *buf);

        1、struct msqid_ds *buf:指向权限信息结构体的指针。

struct msqid_ds{
    uid_t msg_perm.uid;//用户id
    uid_t msg_perm.gid;//用户所在组id
    mode_t msg_perm.mode;//权限值
}

        2、command:函数采取的动作:

命令说明
IPC_STAT获取消息队列对本进程的权限设置
IPC_SET将结构体中的值设置给消息队列
IPC_RMID删除消息队列

3、实操

接收消息进程Reader.c:

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<errno.h>

#include<sys/msg.h>
#define BUFFSIZE 1024

struct my_msg{  //消息结构体
    long int massage_type;
    char text[BUFFSIZE];
};

int main(){
    //以键值1234创建消息队列
    int msgid = msgget((key_t)1234,0666 | IPC_CREAT);
    if(msgid==-1){
        fprintf(stderr,"msgget failed with error: %d\n",errno);
        exit(1);
    }

    struct my_msg recv_data;//消息结构体用于接收消息
    while(1){
        //接收消息
        if(msgrcv(msgid, (void*)&recv_data,
                    BUFFSIZE,0,0)==-1){//0:按顺序接收消息,无消息时阻塞
            fprintf(stderr,"msgrcv failed with error: %d\n",errno);
            exit(1);
        }
        printf("read: %s",recv_data.text);
        if(strncmp(recv_data.text,"end",3)==0){//以end为通信结束标志
            break;
        }
    }
    //删除消息队列
    if(msgctl(msgid,IPC_RMID,NULL)==-1){
        fprintf(stderr,"msgctl(IPC_RMID) failed\n");
        exit(1);
    }
    exit(0);
}

发送消息进程Writer.c:

#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<errno.h>

#include<sys/msg.h>
#define BUFFSIZE 1024

struct my_msg{
    long int massage_type;
    char text[BUFFSIZE];
};

int main(){
    //以相同key值获取消息队列的描述符
    int msgid = msgget((key_t)1234,0666 | IPC_CREAT);
    if(msgid==-1){
        fprintf(stderr,"msgget failed with error: %d\n",errno);
        exit(1);
    }

    struct my_msg send_data;
    char buff[BUFFSIZE]={0};
    while(1){
        printf("Enter some text: ");
        fgets(buff,BUFFSIZE,stdin);
        send_data.massage_type=1;//消息类型为1
        strncpy(send_data.text,buff,BUFFSIZE);
        //发送消息
        if(msgsnd(msgid,(void*)&send_data,
                    BUFFSIZE,0)==-1){//消息队列满时阻塞
            fprintf(stderr,"msgsnd failed\n");
            exit(1);
        }

        if(strncmp(buff,"end",3)==0){
            break;
        }
    }
    exit(0);
}

        分别执行两进程:写进程等待数据写入,还未向消息队列写入消息,因而读进程阻塞。

        写端写入消息后,消息队列中有消息,读端从阻塞转入运行状态,接收消息后打印。再次等待写端向消息队列写入消息。

        写端写入end,通信终止。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值