进程间通信——IPC机制(二)消息队列
目录
前言
一、什么是消息队列
二、创建消息队列的函数
前言
在之前我的博客中讲述了传统的进程间通信方式,即通过管道传输,信号辅助;
本文主要讲述消息的通信方式,即通过消息队列,和共享文件进行传输数据,后面也会使用信号灯、同步互斥机制来控制传输顺序。
一、什么是消息队列
消息队列就是在内核中创建一个队列,进程会将数据打包成结点,添加到队尾,进程也可以从队头读取结点,实现进程的通信(先进先出的通信)
消息队列的特点:
- 消息队列的消息有固定的格式(消息的类型+消息的正文)
消息队列根据先进先出原则读取数据,同时可以指定消息的类型进行读取
消息队列独立于进程
使用消息队列传输数据时,只有当两个进程都结束,消息队列才会被释放
二、创建消息队列的函数
1、msgget():创建消息队列
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int msgflg); 功能:通过key值,创建或打开一个key值对应的消息队列 参数: 参数1: key_t key: key值 参数2: int msgflg: IPC_CREAT:如果key值对应的消息队列不存在,则创建消息队列 IPC_CREAT | 0664 :创建的同时指定权限,如果消息队列已经存在,则会忽略这个权限 返回值: 成功,返回消息队列的对应id 失败,返回-1
2、msgsed():发送消息到消息队列中
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msqid, const void *msgp, size_t msgsz , int msgflg); 功能:向消息队列中发送消息 参数: 参数1: int msqid:消息队列的id,指定进程要发送到哪个消息队列中 参数2: const void *msgp:指定要发送的消息的数据地址 消息格式:----自定义 struct msgbuf { long mtype;消息类型-------发送时,消息类型 > 0 xxx mtext[xxx];消息的正文数据 }; 参数3: size_t msgsz:消息正文数据的大小, mtext大小 参数4: int msgflg:发送方式 0:默认方式,当消息队列满了,msgsnd会阻塞等待 IPC_NOWAIT:非阻塞方式,当消息队列满了,msgsnd 不会阻塞等待,直接结束当前函数,不发送 返回值: 成功,返回0 失败,返回-1
3、msgrcv():从指定的消息队列中读取数据
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); 功能:从指定的消息队列中读取消息 参数: 参数1: int msqid:要读取消息的消息队列id 参数2: void *msgp:指定要将读取的消息存储在哪个地址,注意,以什么类型写入消息队列,就以什么类型从消息队列中读取 消息格式:----自定义 struct msgbuf { long mtype;消息类型 xxx mtext[xxx];消息的正文数据 }; 参数3: size_t msgsz:消息正文大小, mtext大小 参数4: long msgtyp:要读取的消息的类型 msgtyp > 0 :读取消息队列中,指定 msgtyp 类型消息的第一条消息 msgtyp == 0 :读取消息队列中第一条消息 参数5: int msgflg:接收方式 0:默认方式,当消息队列没有数据时,msgrcv会阻塞等待 IPC_NOWAIT:非阻塞方式,当消息队列没有数据时,msgrcv 不会阻塞等待,直接结束当前函数,不接收 返回值: 成功,返回0 失败,返回-1
4、msgctl():控制消息队列的函数,可以实现删除,获取队列信息等等的功能
IPC_NOWAIT:非阻塞方式,当消息队列没有数据时,msgrcv 不会阻塞等待,直接结束当前函数,不接收 返回值: 成功,返回0 失败,返回-1 4、msgctl #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgctl(int msqid, int cmd, struct msqid_ds *buf); 功能:控制消息队列,主要用于删除消息队列 参数: 参数1: int msqid:要控制操作的消息队列id 参数2: int cmd:控制命令 IPC_STAT:获取消息队列属性,获取的属性值存储到 第三个参数 指针变量 对应的地址空间 IPC_SET:设置消息队列属性,把 第三个参数 指针变量对应空间的属性值 设置到消息队列中 IPC_RMID:删除消息队列, 第三个参数为 NULL 返回值: 成功,返回0 失败,返回-1
例如,现在我要实现1.c和2.c之间的通信,如下:
1.c
//用消息队列实现两个进程之间的通信 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define MSG_SIZE 80 //定义消息队列的结点 struct my_msg { long int type; char buf[MSG_SIZE]; }; int main(void) { int msgid; int ret; struct my_msg msg; //创建消息队列 msgid = msgget((key_t)1235, 0666|IPC_CREAT); if (msgid == -1) { printf("msgget failed!\n"); exit(1);//如果创建失败,结束进程 } while(1){ scanf("%ld",&(msg.type)); scanf("%s",msg.buf); // 传入0:如果消息队列满了,那么就阻塞 ret = msgsnd(msgid, &msg, MSG_SIZE, 0); if (strcmp(msg.buf,"quit")==0) { printf("msgsnd failed!\n"); break; } } //删除队列 msgctl(msgid,IPC_RMID,NULL); return 0; }
2.c
//接收消息队列的信息 #include<stdio.h> #include<string.h> #include<sys/ipc.h> #include<sys/types.h> #include<sys/msg.h> struct my_msg { long type; char buf[80]; }; int main(int argc, const char *argv[]) { //创建或者打开消息队列 int msgid; msgid=msgget((key_t)1235,IPC_CREAT | 0664); if(msgid<0) { perror("msgget failed:"); return -1; } //从消息队列中读取数据 while(1) { struct my_msg my_data; int num; //输入队列下标获取对应数据 scanf("%d",&num); //获取队列中的数据 msgrcv(msgid,&my_data,sizeof(struct my_msg)-sizeof(long),num,0); printf("type=%ld,buf=%s \n",my_data.type,my_data.buf); if(strcmp(my_data.buf,"quit")==0) { break; } } //关闭消息队列 msgctl(msgid,IPC_RMID,NULL); return 0; }