学习笔记——进程间通信之消息队列详解


敲黑板!!!

消息队列,是消息的链接表,存放在内核中,是在消息的传输过程中保存消息的容器。。一个消息队列由一个标识符(即队列ID)来标识。

消息队列

特点

  1. 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。

  2. 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。

  3. 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。

看个图
在这里插入图片描述
在这里不用去管Linux内核如何去操作,我们需要关心在一次收发消息中,A或者B如何发送消息的,同时又是如何接收消息的。每一次过程都是通过指定的或者说相同的id去找到相应的结构体的mtext消息进行read或者write

原型

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

// 创建或打开消息队列:成功返回队列ID,失败返回-1
int msgget(key_t key, int flag);
// 添加消息:成功返回0,失败返回-1
int msgsnd(int msqid, const void *ptr, size_t size, int flag)
 // 读取消息:成功返回消息数据的长度,失败返回-1
int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
// 控制消息队列:成功返回0,失败返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

msgget()函数

int msgget(key_t key, int flag);
功能:

创建或打开消息队列。
在以下两种情况下,msgget将创建一个新的消息队列。

  1. 如果没有与键值key相对应的消息队列,并且flag中包含了IPC_CREAT标志位。
  2. key参数为IPC_PRIVATE。

参数:
key:消息队列的id值
msgflg:是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。msgflg可以与IPC_CREAT做或操作(IPC_CREAT|0777,后面加上文件执行权限),表示当key所命名的消息队列不存在时创建一个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被忽略,而只返回一个标识符。

返回值:
成功返回队列id,失败则返回‐1,


msgsnd()函数

int msgsnd(int msqid, const void *ptr, size_t size, int flag)

功能:
读取消息,成功返回消息数据的长度,失败返回‐1

参数:
msgid:消息队列的ID
msgp:指向消息信息的指针,man手册中给出的结构体msgbuf如下:

struct msgbuf
{
       long mtype; //消息类型
       char mtext[1]; //消息正文
};

size:消息的字节数
flag:

IPC_NOWAIT 消息没有发送完成,函数也会立即返回
0 知道发送完成,函数才返回

注意:
这个别写错了。。。。。我就容易写成msgsend


msgrcv()函数

int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);

功能:
获取消息队列的消息

参数:
msgid:消息队列的ID
msgp:要接收消息的缓冲区
size:要接收的消息的字节数
msgtype:

type == 0,返回队列中的第一个消息;
type > 0,返回队列中消息类型为 type 的第一个消息;
type < 0,返回队列中消息类型值小于或等于 type 绝对值的消息,如果有多个,则取类型值最小的消息。

flag:
0:若无消息函数一直阻塞
IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG。

返回值:
成功:接收到的消息i长度
出错:‐1


msgctl()函数

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

功能:
控制消息队列,成功返回0,失败返回‐1

参数:
msqid:消息队列的队列ID
cmd:
IPC_RMID:删除消息队列
buf:NULL吧





再补充下ftok函数,等会demo用得到


ftok()函数
NAME
       ftok  - convert a pathname and a project identifier to a System
       V IPC key

SYNOPSIS
       #include <sys/types.h>
       #include <sys/ipc.h>//头文件

       key_t ftok(const char *pathname, int proj_id);

以下是百度:
系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。

函数原型:
key_t ftok( const char * fname, int id )
fname就是你指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key;
key = ftok(“.”, 1); 这样就是将fname设为当前目录。
id是子序号。虽然是int类型,但是只使用8bits(1-255)。
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
查询文件索引节点号的方法是: ls -i
当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来不同,所以得到的索引节点号也不同。

我们上个图看看好理解不?
在这里插入图片描述
一个点代表本机目录,两个代表上级目录,前面的是索引节点号, key = ftok(“.”,7);比如我们这样写就是本机目录和数字7他们变换的16进制。同样的 key = ftok(“.”,‘o’);字符也是可以的。

ftok函数
当成功执行的时候,一个key_t值将会被返回,否则 ‐1 被返回。


demo实例

接下来看看这个demo实例

这是msgget.c文件

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>

struct msgbuf {
	long mtype;       /* message type, must be > 0 */
        char mtext[256];    /* message data */
};



int main(){
	int msgid;
	key_t key;
	struct msgbuf getbuf;
	struct msgbuf sendbuf = {988,"hello,i am msgget"};
//      key_t ftok(const char *pathname, int proj_id);
	key = ftok(".",'o');
	printf("key = %x\n",key);
//      int msgget(key_t key, int msgflg);
	msgid = msgget(key,IPC_CREAT|0777);
	if(msgid == -1){
		printf("create queue failed!\n");
		exit(1);
	}
//      ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
	msgrcv(msgid,&getbuf,sizeof(getbuf.mtext),888,0);
	printf("Received send message:%s\n",getbuf.mtext);
//	int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
	msgsnd(msgid,&sendbuf,sizeof(sendbuf.mtext),0);
//      int msgctl(int msqid, int cmd, struct msqid_ds *buf);
	msgctl(msgid,IPC_RMID,NULL);
	return 0;
}

这是msgsend.c文件

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>

struct msgbuf {
	long mtype;       /* message type, must be > 0 */
        char mtext[256];    /* message data */
};



int main(){
	int msgid;
	key_t key;
	struct msgbuf getbuf = {888,"hello,i am msgsend"};
	struct msgbuf sendbuf;
//      key_t ftok(const char *pathname, int proj_id);
	key = ftok(".",'o');
	printf("key = %x\n",key);
//      int msgget(key_t key, int msgflg);
	msgid = msgget(key,IPC_CREAT|0777);
	if(msgid == -1){
		printf("create queue failed!\n");
		exit(1);
	}
//      ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
	msgsnd(msgid,&getbuf,sizeof(getbuf.mtext),0);
//	int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
	msgrcv(msgid,&sendbuf,sizeof(sendbuf.mtext),988,0);
	printf("Received get message:%s\n",sendbuf.mtext);
//      int msgctl(int msqid, int cmd, struct msqid_ds *buf);
	msgctl(msgid,IPC_RMID,NULL);
	return 0;
}

结果如下:

在这里插入图片描述

ending!!!!

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

石子君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值