linux--消息队列

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ferlan/article/details/84190369

什么是消息队列

消息队列实际上是操作系统在内核为我们创建的一个队列.

关于组织一个带有类型的数据块,添加到队列中,其他的进程从队列中获取数据块.也就是说消息队列传输的是一个个带有类型的数据块.

消息队列是一个全双工通信,两个进程都可读可写.

在命令行中可以使用ipcs -q查看消息队列.
也可以使用ipcrm -q+msgid删除对应的消息队列

消息队列的生命周期随内核,不随进程,这就意味这如果不手动关闭消息队列且不重启计算机,那消息队列将一直存在与内核中.

struct msqid_ds {
struct ipc_perm msg_perm;
struct msg *msg_first; /* first message on queue,unused */
struct msg *msg_last; /* last message in queue,unused */
__kernel_time_t msg_stime; /* last msgsnd time */
__kernel_time_t msg_rtime; /* last msgrcv time */
__kernel_time_t msg_ctime; /* last change time */
unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */
unsigned long msg_lqbytes; /* ditto */
unsigned short msg_cbytes; /* current number of bytes on queue */
unsigned short msg_qnum; /* number of messages in queue */
unsigned short msg_qbytes; /* max number of bytes on queue */
__kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */
__kernel_ipc_pid_t msg_lrpid; /* last receive pid */
};


struct msgbuf {//队列中节点结构体,需要自己定义
long mtype;
char mtext[1];
}

消息队列的应用函数

创建消息队列

功能:⽤来创建和访问⼀个消息队列
原型
int msgget(key_t key, int msgflg);
参数
key: 内核中某个消息队列的标识

msgflg:由九个权限标志构成,它们的⽤法和创建⽂件时使⽤的mode模式标
		IPC_CREAT:   不存在则创建,存在则打开
		IPC_EXCL:    与IPC_CREAT同用时,若存在则报错
		mode:        倘若用IPC_CREAT创建则需要赋予权限
		
返回值:成功返回⼀个⾮负整数,即该消息队列的标识码;失败返回-1

发送数据/接收数据

msgsnd函数
功能:把⼀条消息添加到消息队列中
原型
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
参数
msgid: 由msgget函数返回的消息队列标识码

msgp:是⼀个指针,指针指向准备发送的消息,

msgsz:是msgp指向的消息⻓度,这个⻓度不含保存消息类型的那个long int⻓整型

msgflg:控制着当前消息队列满或到达系统上限时将要发⽣的事情

msgflg=IPC_NOWAIT表⽰队列满不等待,返回EAGAIN错误。

返回值:成功返回0;失败返回-1

功能:是从⼀个消息队列接收消息
原型:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg
参数
msgid: 由msgget函数返回的消息队列标识码

msgp:是⼀个指针,指针指向准备接收的消息,

msgsz:是msgp指向的消息⻓度,这个⻓度不含保存消息类型的那个long int⻓整型

msgtype:它可以实现接收优先级的简单形式
			取0:按照队列的排列顺序接收
			>0:取对应msgtype的数据,比如取3 就接收3号类型的数据的第一个节点
			<0:接收小于msgtype绝对值的第一个节点,比如取-3,就接收第一个1,2号节点

msgflg:控制着队列中没有相应类型的消息可供接收时将要发⽣的事
		默认为0
		MSG_NOERROR 当数据长度超过指定长度,则截断数据
		
返回值:成功返回实际放到接收缓冲区⾥去的字符个数,失败返回-1

释放消息队列

功能:消息队列的控制函数
原型
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数
msqid: 由msgget函数返回的消息队列标识码
cmd:是将要采取的动作,(有三个可取值)
返回值:成功返回0,失败返回-1

利用消息队列实现进程间通信

  1. 创建消息队列
  2. 发送数据/接收数据
  3. 释放消息队列

msgqueue_c.c

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 #include <errno.h>
  6 #include <sys/msg.h>
  7 #include <sys/ipc.h>
  8 
  9 //这个时消息队列的key
 10 #define IPC_KEY 0x12345678
 11 //下边这两个宏,用于我们赋值我们传输的数据块的类型
 12 #define TYPE_S  1   //你是什么端就接收什么类型的数据,S端接收TYPE_S,  
 13 #define TYPE_C  2   // C端接收TYPE_C
 14 
 15 struct msgbuf { //之所以要我们自己定义,是因为每条数据的最大长度要自己设定  
 16     long mtype;       /* message type, must be > 0 */
 17     char mtext[1024];    /* message data */
 18 };  
 19 int main()
 20 {
 21     int msgid = -1;
 22     
 23     //ftok
 24     //key_t ftok(const char *pathname, int proj_id);
 25     //ftok通过文件的inode节点号和一个proj_id计算得出一个key值
 26     //缺点:如果文件被删除,或替换,那么将打开的不是同一个msgqueue
 27     //1. 创建消息队列
 28     msgid = msgget(IPC_KEY, IPC_CREAT | 0664);
 29     if (msgid < 0) {
 30         perror("msgget error");
 31         return -1;
 32     }
 33     while(1) {
 34         struct msgbuf buf;
 35         //发送数据
 36         memset(&buf, 0x00, sizeof(struct msgbuf));
 37         buf.mtype = TYPE_C;
 38         scanf("%s", buf.mtext);
 39         msgsnd(msgid, &buf, 1024, 0);
 40         //接收数据
 41         memset(&buf, 0x00, sizeof(struct msgbuf));
 42         msgrcv(msgid, &buf, 1024, TYPE_S, 0);
 43         printf("boy say:[%s]\n", buf.mtext);
 44 
 45     }
 46     //IPC_RMID  删除IPC
 47     msgctl(msgid, IPC_RMID, NULL);
 48 }

msgqueue_s.c

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 #include <errno.h>
  6 #include <sys/msg.h>
  7 #include <sys/ipc.h>
  8 
  9 //这个时消息队列的key
 10 #define IPC_KEY 0x12345678
 11 //下边这两个宏,用于我们赋值我们传输的数据块的类型
 12 #define TYPE_S  1 //send
 13 #define TYPE_C  2 //recv
 14 
 15 struct msgbuf {
 16     long mtype;       /* message type, must be > 0 */
 17     char mtext[1024];    /* message data */
 18 };
 19 int main()
 20 {
 21     int msgid = -1;
 22 
 23     //ftok
 24     //key_t ftok(const char *pathname, int proj_id);
 25     //ftok通过文件的inode节点号和一个proj_id计算得出一个key值
 26     //缺点:如果文件被删除,或替换,得到的inode节点号就改变了。那么将打开的不是同一个msgqueue
 27 
 28     //1. 创建消息队列
 29     msgid = msgget(IPC_KEY, IPC_CREAT | 0664);
 30     if (msgid < 0) {
 31         perror("msgget error");
 32         return -1;
 33     }
 34     while(1) {
 35         //接收数据
 36         struct msgbuf buf;
 37         //msgrcv    默认阻塞的获取数据
 38         //msgid:    操作句柄
 39         //buf:     接收数据的结构体,需要自己定义
 40         //1024:    用于指定要接收的最大数据长度,不包含mtype
 41         //TYPE_C:  用于指定接收的数据类型
 42         //msgflag: 0-默认
 43         //      MSG_NOERROR 当数据长度超过指定长度,则截断数据
 44         msgrcv(msgid, &buf, 1024, TYPE_C, 0);
 45         printf("girl say:[%s]\n", buf.mtext);
 46         //发送数据
 47         memset(&buf, 0x00, sizeof(struct msgbuf));
 48         buf.mtype = TYPE_S;
 49         scanf("%s", buf.mtext);
 50         msgsnd(msgid, &buf, 1024, 0);
 51 
 52     }
 53     //IPC_RMID  删除IPC
 54     msgctl(msgid, IPC_RMID, NULL);
 55 }

当两个都执行起来后,就可以进行通信了
在这里插入图片描述

消息队列的不足

消息队列也有管道⼀样的不⾜,就是每个消息的最⼤⻓度是有上限的(MSGMAX),每个消息队
列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有⼀个上限(MSGMNI)

猜你喜欢

转载自blog.csdn.net/Ferlan/article/details/84190369