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

文章目录

    • 消息队列
      • 特点
      • 原型
        • msgget()函数
        • msgsnd()函数
        • msgrcv()函数
        • msgctl()函数
        • ftok()函数
        • demo实例

敲黑板!!!

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

消息队列

特点

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

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

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

看个图
学习笔记——进程间通信之消息队列详解_第1张图片
在这里不用去管Linux内核如何去操作,我们需要关心在一次收发消息中,A或者B如何发送消息的,同时又是如何接收消息的。每一次过程都是通过指定的或者说相同的id去找到相应的结构体的mtext消息进行read或者write

原型

#include 
#include 
#include 

// 创建或打开消息队列:成功返回队列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 
       #include //头文件

       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
当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来不同,所以得到的索引节点号也不同。

我们上个图看看好理解不?
学习笔记——进程间通信之消息队列详解_第2张图片
一个点代表本机目录,两个代表上级目录,前面的是索引节点号, key = ftok(“.”,7);比如我们这样写就是本机目录和数字7他们变换的16进制。同样的 key = ftok(“.”,‘o’);字符也是可以的。

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


demo实例

接下来看看这个demo实例

这是msgget.c文件

#include 
#include 
#include 
#include 
#include 
#include 

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 
#include 
#include 
#include 
#include 
#include 

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!!!!

你可能感兴趣的:(Linux,学习,linux,c语言)