进程间通信之消息队列

    技术2022-05-19  25

            消息队列的使用同管道类似,但是 消息队列可以允许通过规定的消息类型来区分,消息接收者可以请求可用的消息而忽略消息类型(定义消息类型为0),或者它也可以请求接收指定的消息类型的消息(定义消息类型为正整数)。消息队列用于运行在统一台计算机上的进程间的通信。         对消息队列的操作基本有通过调用ftok函数产生唯一的key,根据该key创建消息队列,通过msgsnd想消息队列发送信息,通过msgrcv接收消息队列中的信息,通过msgctl删除消息队列。其各个函数的函数原型为: #include<sys/types.h> #include<sys/ipc.h> key_t ftok(const char *pathname, int proj_id); pathname 指定的已存在的文件名,一般使用当前目录, 例如:key_t key=ftok(".",1);为当前目录创建唯一的key 返回值: 成功则返回key, 出错则返回-1. 参数: pathname参数必须引用一个现存文件.当产生key时只使用id参数的低8位。 msgget可以创建一个消息队列,并且返回队列标志符。 #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> int msgget(key_t key, int msgflag); 参数:   key:消息队列关联的键。   msgflag:消息队列的建立标志和存取权限。如果单独使用IPC_CREAT,则msgget()要么返回一个新创建的消息队列的标识符,要么返回具有相同关键字值的队列的标识符。如果 IPC_EXCL和IPC_CREAT一起使用,则msgget()要么创建一个新的消息队列,要么如果队列已经存在则返回一个失败值-1。 IPC_EXCL单独使用是没有用处的。 返回说明:    成功执行时,返回消息队列标识值。失败返回-1,errno被设为以下的某个值   EACCES:指定的消息队列已存在,但调用进程没有权限访问它,而且不拥有CAP_IPC_OWNER权能   EEXIST:key指定的消息队列已存在,而msgflg中同时指定IPC_CREAT和IPC_EXCL标志   ENOENT:key指定的消息队列不存在同时msgflg中不指定IPC_CREAT标志   ENOMEM:需要建立消息队列,但内存不足   ENOSPC:需要建立消息队列,但已达到系统的限制    msgsnd函数将数据放入到消息队列中,其函数原型为: #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> int msgsnd(int msgid, const void * msgp, size_t msgsz, int msgflag); 参数:     msgid,消息管道的id,由msgget函数返回。     msgp为调用者定义的一个结构指针,该结构类型为     struct msgbuf{         long mtype;         char mtext[1];     };     mtext是一个字符数组或者其他类型的结构体,它的大小有msgsz指定,msgbuf.mtype 必须为非负整数。     msgflag为位掩码,可通过或操作叠加,可为0,其值可为:     IPC_NOWAIT:若队列中没有指定类型的数据,则立即返回     MSG_EXCEPT:接收消息队列中第一个类型不是为mtype的消息     MSG_NOERROR:若消息长于msgsz字节,则该消息被截断 返回值:成功返回0,出错返回-1 #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag); 参数:     * ptr: 指向一个长整型数(返回的消息类型存放在其中), 跟随其后的是存放实际消息数据的缓冲区.     * nbytes: 数据缓冲区的长度. 若返回的消息大于nbytes, 且在flag中设置了MSG_NOERROR, 则该消息被截短.     * type:         type == 0: 返回队列中的第一个消息.         type > 0: 返回队列中消息类型为type的第一个消息. 返回值: 成功则返回消息的数据部分的长度, 出错则返回-1.    #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> int msgctl(int msqid, int cmd, struct msgqid_ds *buf); 返回值: 成功则返回0, 出错则返回-1. 参数: cmd参数说明对msqid指定的队列要执行的命令:     * IPC_STAT: 取此队列的msqid_ds结构, 并将它存放在buf指向的结构中.     * IPC_SET: 按由buf指向结构中的值, 设置与此队列相关结构中的msg_perm.uid, msg_perm.gid, msg_perm.mode和msg_qbytes. 该命令只有下列两种进程可以执行:      有效用户ID等于msg_perm.cuid或msg_per.uid.      具有超级用户特权的进程.      IPC_RMID: 从系统中删除该消息队列以及仍在该队列中的所有数据. 执行权限同上.

    例子: #include<stdio.h> #include<sys/types.h> #include<sys/msg.h> #include<sys/ipc.h> struct amsgbuf{ long mtype; char mtext[80]; }mq_test_buf; int main(void) { key_t unique_key; int id; int i; unique_key=ftok(".",56);//创建唯一的key printf("Unique key is: %d/n",unique_key); id=msgget(unique_key,IPC_CREAT|0666);//创建或返回消息队列 printf("message queue id=%d/n", id); if(id==-1){ perror("Error creating/connecting to message queue/n"); return 0; } //将消息类型为123的消息写入消息队列中 printf("Sending message.../n"); mq_test_buf.mtype=123; sprintf(mq_test_buf.mtext,"test message"); if(msgsnd(id,(struct msgbuf *)&mq_test_buf,sizeof("test message")+1,0)==-1){ perror("Error sending message/n"); return 0; } //清空mq_test_buf中数据部分的数据,确保以后的数据是从消息队列中收到的 mq_test_buf.mtext[0]=0; //从消息队列中读取类型为123的消息 i=msgrcv(id,(struct msgbuf *)&mq_test_buf, 80,123,IPC_NOWAIT); if(i==-1){ printf("No message is avaliable of type 123/n"); }else { printf("Message of type 123 received with data: %s/n",mq_test_buf.mtext); } //删除消息队列 msgctl(id, IPC_RMID,0); return 0; }


    最新回复(0)