嵌入式学习——进程间通信方式(4)—— 消息队列
一、基本概念
消息队列是一个进程向另一个进程发送一个数据块,每个数据块都含有一个类型,接收方可以接收自己想要的消息类型。
消息队列、信号的区别:信号能承载的数据量较小,而队列能够存放大量自定义的数据。
消息队列、管道的区别:
① 、有名管道和消息队列都可以通过不同进程传输数据,都是要发送和接收数据,但是有名管道利用的是read()、write()函数,而消息队列则是通过msgsnd()、msgrev()。
②、管道只能传输无字节流的数据,而消息队列可以支持各种类型的数据,有格式的字节流
③、消息队列可以选择想要读取的数据,可以根据消息类型来接收,而管道只能按数据流读取出来(像水管一样)。
二、基本流程
1)创建或获取一个消息队列对象
int msgget(key_t key, int msgflg);
key:不同的进程可以通过访问相同的key,来操作同一个消息队列,实现数据的传输,其中可以利用宏IPC_PRIVATE,这个宏的取值为0,创建当前进程的私有消息队列。
msgflg:创建消息队列模式的参数
O_CREAT:如果不存在相同key的消息队列,则创建一个;如果存在相同的消息队列,则返回标识符msqid。一般在创建时与0600进行位运算 O_CREAT | 0600,给创建的文件指定一个权限。
O_CREAT | O_EXCL:表示如果这个key在内核存在一个消息队列则返回一个错误描述,如果不存在则创建一个。
2)封装消息的结构体
struct msgbuf {long mtype; /* 消息类型必须大于0 */char mtext[1]; /* 消息内容,可以是其他任何类型*/};
3)发送、接收消息队列
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
msqid:就是创建消息队列时返回的标识符
msgp:封装消息的结构体
msgsz:封装消息结构体的大小,不包含消息类型占用的4个字节,即mtext的长度。
msgflg:如果为0则表示:当消息队列满时,msgsnd()函数将会阻塞,直到消息能写进消息队列; 如果为IPC_NOWAIT则表示:当消息队列已满的时候,msgsnd()函数不等待立即返回; 如果为IPC_NOERROR:若发送的消息大于size字节,则把该消息截断,截断部分将被丢弃,且不通知发送进程。
4)销毁消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msqid:消息队列的标识符。
cmd:常用的控制命令如下:
IPC_RMID:删除该消息队列
IPC_STAT:获取属性权限,放到buf中
IPC_SET:设置属性信息为buf指向的内容。
IPC_INFO:获得关于消息队列的系统限制值信息。
SHM_INFO:获得系统为消息队列消耗的资源信息。
buf:在释放共享内存时,为NULL即可。
struct shmid_ds {struct ipc_perm shm_perm; /* Ownership and permissions */size_t shm_segsz; /* Size of segment (bytes) */time_t shm_atime; /* Last attach time */time_t shm_dtime; /* Last detach time */time_t shm_ctime; /* Last change time */pid_t shm_cpid; /* PID of creator */pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */shmatt_t shm_nattch; /* No. of current attaches */...};
struct ipc_perm {key_t __key; /* Key supplied to shmget(2) */uid_t uid; /* Effective UID of owner */gid_t gid; /* Effective GID of owner */uid_t cuid; /* Effective UID of creator */gid_t cgid; /* Effective GID of creator */unsigned short mode; /* Permissions + SHM_DEST andSHM_LOCKED flags */unsigned short __seq; /* Sequence number */};
三、代码示例
1)发送端的代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>
//封装消息结构体
struct msgget
{long mtype;char mdata[128];
};int main()
{key_t key = ftok("/bin/bash",1);//创建消息队列int msqid = msgget(key,IPC_CREAT | 0600);if(msqid == -1){perror("create msqid failed");return -1;}struct msgget message;message.mtype = 1;strcpy(message.mdata,"hello,new friend");//发送消息队列int ret = msgsnd(msqid,&message,sizeof(message.mdata),0);if(ret == -1){perror("message send failed");}printf("send message success\n");return 0;}
2)接收端的代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>//封装消息结构体
struct msgget
{long mtype;char mdata[128];
};int main()
{key_t key = ftok("/bin/bash",1);//创建消息队列int msqid = msgget(key,IPC_CREAT | 0600);if(msqid == -1){perror("create msqid failed");return -1;}struct msgget message;//接收消息队列int ret = msgrcv(msqid,&message,sizeof(message.mdata),0,0);if(ret == -1){perror("message send failed");}printf("收到的消息是:%s\n",message.mdata);//销毁消息队列msgctl(msqid,IPC_RMID,NULL);return 0;}