当前位置: 首页 > 科技观察

Linux中消息队列的使用

时间:2023-03-12 23:01:19 科技观察

今天带小伙伴们来学习一下消息队列。首先简单介绍消息队列,然后学习消息队列相关的结构体和函数。最后,我将使用代码来使用这些功能。消息队列,希望对大家有所帮助!1消息队列的概念及使用过程1)消息队列的概念消息队列是消息的链表。一条消息可以看作是一条数据记录,这条数据有特定的格式。进程可以根据特定的规则向队列中添加(写入)消息;其他进程可以从消息队列中读取消息。2)消息队列的应用场景消息队列本身就是IPC通信的内容,所以主要用于进程间通信。消息可以读写,所以发送的消息可以作为动作通知信号,或者接收数据再做其他处理。2消息队列相关的结构体和函数0)消息队列相关的结构体每个队列都有一个与之相关联的msqid_ds结构体,结构体如下。structmsqid_ds{structipc_permmsg_perm;//消息队列的访问权限和其他一些信息time_tmsg_stime;//队列最后一次收到消息的时间time_tmsg_rtime;//消息最后一次被取出队列的时间time_tmsg_ctime;//最后一次timethequeuechangedtimeunsignedlong__msg_cbytes;//队列中消息占用内存的字节数msgqnum_tmsg_qnum;//当前队列中的消息数msglen_tmsg_qbytes;//队列中占用内存的最大字节数pid_tmsg_lspid;//上次向队列发送消息的进程pidmsgsndpid_tmsg_lrpid;//上次从队列中取出消息的进程的pid};structipc_perm{key_tkey;ushortuid;//用户id,有效用户id和effectivegroupid(euidandegid)ushortgid;ushortcuid;//创建用户的euid和egidushortcgid;ushortmode;//访问模式,见模式标志ushortseq;//IPC对象使用频率信息};1)msgget函数msgget函数用于创建或打开一个消息队列。①函数原型。intmsgget(key_tkey,intmsgflg)②头文件。includeincludeinclude③参数。键:键值。msgflg:打开标志。IPC_CREAT:表示一个新创建的消息队列。④返回值。成功:返回消息队列的id。失败:-1。2)msgsnd函数msgsnd函数用于发送消息,即向消息队列写入消息。①函数原型。intmsgsnd(intmsgid,constvoid*msgp,size_tmsgsz,intmsgflg)②头文件。includeincludeinclude③参数。msgid:消息队列的id。msgp:指向要发送的消息。msgsz:消息的长度。msgflg:标志位。④返回值。成功:0。失败:-1。3)msgrcv函数msgrcv函数用于读取消息队列,即从消息队列中接收消息。①函数原型。intmsgsnd(intmsqid,constvoid*msgp,size_tmsgsz,intmsgflg)ssize_tmsgrcv(intmsqid,void*msgp,size_tmsgsz,longmsgtyp,intmsgflg)②头文件。#include#include#include③参数。msqid:消息队列的id。msgp:存储消息。msgsz:要获取的消息的最大长度。msgtyp:消息的类型,分为以下三种情况:当msgtyp=0时:忽略类型,直接取队列中的第一条消息。当msgtyp>0时:获取消息队列中类型等于msgtyp的第一条消息。当msgtyp<0时:取类型小于或等于msgtyp绝对值的消息。如果有多个消息满足此条件,则取类型最小的消息。④返回值。成功:实际收到的报文数据长度。失败:-1。4)msgctl函数msgctl函数用于对消息队列进行操作,如删除消息队列等。①函数原型。intmsgctl(intmsqid,intcmd,structmsqid_ds*buf)②头文件。#include#include#include③参数。msqid:消息队列的id。cmd:消息队列的操作命令。此参数指定要在msqid指定的队列上执行的命令。IPC_STAT:取这个队列的msqidds结构,存放在buf指向的结构中。IPCSET:将字段msg_perm.uid、msg_perm.gid、msg_perm.mode和msg_qbytes从buf指向的结构复制到与该队列关联的msqid_ds结构中。此命令只能由以下两个进程执行:一个有效用户ID等于msg_perm.cuid或msgperm.uid。另一个是具有超级用户权限的进程。只有超级用户可以增加msg_qbytes的值。IPC_RMID:从系统中删除消息队列和队列中的所有数据。此类删除立即生效。仍在使用此消息队列的其他进程在下次尝试对此队列进行操作时将收到EIDRM错误。此命令只能由以下两个进程执行:一个有效用户ID等于msg_perm.cuid或msg_perm.uid。另一个是具有超级用户权限的进程。这3个命令(IPC_STAT、IPC_SET和IPC_RMID)也可用于信号量和共享内存。buf:获取内核中的msqid_ds结构体,一般不用。④返回值。成功:0失败:-1.3下面的示例代码使用两个进程来演示消息队列的使用。示例代码如下,说明都在代码注释、图片中。发送队列.c。#include#include#include#include#include//消息结构structmsg{longmsgtype;//消息的类型charmsgtext[1024];//消息的长度};voidmain(intargc,char*argv[]){intmsgid;charstr[256];structmsgmsgst;key_tkey=ftok("/tmp",600);//创建消息队列msgid=msgget(key,0666|IPC_CREAT);//键盘输入消息while(1){//获取消息数据printf("\nPleaseenteramesagetosend,input'end'toquit!\n\n");scanf("%s",str);strcpy(msgst.msgtext,str);if(strncmp(str,"end",3)==0){printf("\n");break;}//发送消息msgsnd(msgid,&msgst,sizeof(structmsg),0);}//输出消息队列msgctl(msgid,IPC_RMID,0);}ReceiveQueue.c.#include#include#include#include#include#include//消息结构structmsg{longmsgtype;charmsgtext[1024];};intmain(intargc,char*argv[]){intRunFlag=1;//循环标志intmsgid=-1;//消息idlongmsgtp=0;//消息类型structmsgmsgst;//消息结构variablekey_tkey=ftok("/tmp",600);//创建键值msgid=msgget(key,0666|IPC_CREAT);//创建消息队列if(msgid==-1){exit(1);//异常退出}while(RunFlag)//从队列中获取消息直到遇到结束消息{if(msgrcv(msgid,&msgst,sizeof(structmsg),msgtp,0)==-1){exit(1);//异常退出}printf("\nThemessagereceivedis:%s\n\n",msgst.msgtext);if(strncmp(msgst.msgtext,"end",3)==0)//遇到endEnd{RunFlag=0;//设置退出循环标志}}if(msgctl(msgid,IPC_RMID,0)==-1)//删除消息队列{exit(1);//异常退出}exit(0);//正常退出}编译程序,先运行接收程序,再运行发送程序,输入要发送的信息,输入end退出。①两个终端运行结果如下:②单个终端运行结果如下:本文转载自微信公众号“嵌入式贵族军”,可通过以下二维码关注。转载本文请联系嵌入式杂军公众号。