Linux学习记录(十一)———进程间的通信(消息队列)


4.消息队列

消息队列,是消息的链表,存放在内核中,一个消息队列由一个标识符(队列ID)来标识。

  • 查看消息队列指令
    • ipcs -q
      在这里插入图片描述
4.1特点
  • 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级

  • 消息队列独立于发送和接收进程,进程终止时,消息队列及其内容仍存在

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

4.2.相关函数
1.int msgget(key_t key, int msgflg);
//创建或打开消息队列,
/*
*参数:
*key:和消息队列关联的key值
*msgflg:是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。msgflg可以与IPC_CREAT做或
*操作,表示当key所命名的消息队列不存在时创建一个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被
*忽略,而只返回一个标识符。
*返回值:成功返回队列ID,失败则返回‐1,
 */   
2.int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//控制消息队列,成功返回0,失败返回‐1
/*参数:
*msqid:消息队列的队列ID
*cmd:
*	IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。
*	IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值
*	IPC_RMID:删除消息队列
*buf:是指向 msgid_ds 结构的指针,它指向消息队列模式和访问权限的结构
*返回值:成功:0,失败:‐1*/

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

  • 如果没有与键值key相对应的消息队列,并且flag中包含了IPC_CREAT标志

  • key参数为IPC_PRIVATE

创建/删除一个消息队列

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

int main()
{
	int msgid;
	msgid = msgget(IPC_PRIVATE,0755);//创建消息队列
	if(msgid == -1)
	{
		printf("create message queue failed\n");
		return -1;
	}
	printf("create message queue successed! msgid is %d\n",msgid);
	system("ipcs -q");//查看消息队列
	msgctl(msgid,IPC_RMID,NULL);//删除ID为msgid的消息队列
	system("ipcs -q");
	return 0;
}

在这里插入图片描述

3.int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//读取消息,成功返回消息数据的长度,失败返回‐1
/*
*@param:
*	msgid:消息队列的ID
*	msgp:指向消息的指针,常用结构体msgbuf如下:
*	struct msgbuf
*	{
*		long mtype; //消息类型
*		char mtext[N]; //消息正文
*	}
*	size:发送的消息正文你的字节数
*	flag:
*		IPC_NOWAIT 消息没有发送完成函数也会立即返回
*		0:知道发送完成函数才返回
*@return:成功:0失败:‐1
*/
4.ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
//从一个消息队列中获取消息
/*
*@param:
*	msgid:消息队列的ID
*	msgp:要接收消息的缓冲区
*	size:要接收的消息的字节数
*	msgtype:
*	0:接收消息队列中第一个消息
*	大于0:接收消息队列中第一个类型为msgtyp的消息
*	小于0:接收消息队列中类型值不大于msgtyp的绝对值且类型值又最小的消息。
*	flag:
*	0:若无消息函数一直阻塞
*	IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG。
*@return:成功:接收到的消息i长度,出错:‐1
*/

注意:
    消息队列读取之后结点仍存在,但是内容会被清空!

函数msgrcv在读取消息队列时,type参数有下面几种情况

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

可以看出,type值非0时用于以非先进先出次序读取消息,也可以把type看成优先级的权值

创建一个消息队列发送一个hello world 并读取

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
//定义一个消息缓存的结构体
struct msgbuf
{
	long mtype;
	char mtext[128];
	int ID[4];
};

int main()
{
	ssize_t ret;
	struct msgbuf sndbuf,readbuf;
	int msgid;
	msgid = msgget(IPC_PRIVATE,0755);//创建消息队列
	if(msgid == -1)
	{
		printf("create message queue failed\n");
		return -1;
	}	
	printf("creat message queue successed\n");
	//init struct
	sndbuf.mtype = 100;//给消息队列赋值类型
	printf("please input message:");
	fgets(sndbuf.mtext,128,stdin);//从终端读取要发送的信息
	msgsnd(msgid,(void *)&sndbuf,strlen(sndbuf.mtext),0);//发送一个队列
	system("ipcs -q");
	//read
	memset(readbuf.mtext,0,128);//初始化读队列的文本内容
	ret = msgrcv(msgid,(void *)&readbuf,128,100,0);//读消息队列的内容
	printf("total is %ld byte message is %s\n",ret,readbuf.mtext);
	system("ipcs -q");
	return 0;
}

在这里插入图片描述

ftok函数

key_t ftok( char * fname, int id )
//系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
/*参数:
*fname就时你指定的文件名(该文件必须是存在而且可以访问的)。
*id是子序号, 虽然为int,但是只有8个比特被使用(0‐255)。
*返回值:当成功执行的时候,一个key_t值将会被返回,否则 ‐1 被返回。
*/
消息队列进程间的通信
//msg_write
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>

struct msgbuf
{
	long mtype;
	char mtext[128];
	int ID[4];
};

int main()
{
	ssize_t ret;
	struct msgbuf sndbuf;
	int msgid;
	key_t key;
	key = ftok("a.c",1);
	msgid = msgget(key,IPC_CREAT|0755);
	if(msgid == -1)
	{
		printf("create message queue failed\n");
		return -1;
	}	
	printf("creat message queue successed msgid is %d\n",msgid);
	//init struct
	sndbuf.mtype = 100;
	while(1)
	{
		memset(sndbuf.mtext,0,128);
		printf("please input message:");
		fgets(sndbuf.mtext,128,stdin);
		msgsnd(msgid,(void *)&sndbuf,strlen(sndbuf.mtext),0);
	}
	return 0;
}
//msg_read
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>

struct msgbuf
{
	long mtype;
	char mtext[128];
	int ID[4];
};

int main()
{
	ssize_t ret;
	struct msgbuf readbuf;
	int msgid;
	key_t key;
	key = ftok("a.c",1);
	msgid = msgget(key,IPC_CREAT|0755);
	if(msgid == -1)
	{
		printf("create message queue failed\n");
		return -1;
	}	
	printf("creat message queue successed msgid is %d\n",msgid);
	//read
	while(1)
	{
		memset(readbuf.mtext,0,128);
		ret = msgrcv(msgid,(void *)&readbuf,128,100,0);
		printf("message is %s\n total is %ld byte\n",readbuf.mtext,ret);
	}
	return 0;
}

在这里插入图片描述

消息队列全双工通信

全双工双方都可以发送和接收

父子进程分别实现发送和接收的功能(fork创造出的父子进程互相争抢cpu的使用权)

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

struct msgbuf
{
	long mtype;
	char mtext[128];
	int ID[4];
};

int main()
{
	ssize_t ret;
	struct msgbuf sndbuf,readbuf;
	int msgid;
	pid_t pid;
	key_t key;
	key = ftok("a.c",1);
	msgid = msgget(key,IPC_CREAT|0755);
	if(msgid == -1)
	{
		printf("create message queue failed\n");
		return -1;
	}	
	printf("creat message queue successed msgid is %d\n",msgid);
	//init struct
	sndbuf.mtype = 100;
	//creat child process
	pid = fork();
	if(pid > 0)//write 100 message
	{		
		while(1)
		{
			memset(sndbuf.mtext,0,128);
			printf("please input message:");
			fgets(sndbuf.mtext,128,stdin);
			msgsnd(msgid,(void *)&sndbuf,strlen(sndbuf.mtext),0);
		}
	}
	else if(pid == 0)//read 200 message
	{
		while(1)
		{
			memset(readbuf.mtext,0,128);
			ret = msgrcv(msgid,(void *)&readbuf,128,200,0);
			printf("type 200 :%s\n",readbuf.mtext);
		}

	}
	return 0;
}
//msg_client
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

struct msgbuf
{
	long mtype;
	char mtext[128];
	int ID[4];
};

int main()
{
	ssize_t ret;
	struct msgbuf sndbuf,readbuf;
	int msgid;
	pid_t pid;
	key_t key;
	key = ftok("a.c",1);
	msgid = msgget(key,IPC_CREAT|0755);
	if(msgid == -1)
	{
		printf("create message queue failed\n");
		return -1;
	}	
	printf("creat message queue successed msgid is %d\n",msgid);
	//init struct
	sndbuf.mtype = 200;
	//creat child process
	pid = fork();
	if(pid > 0)//write 200 message
	{		
		while(1)
		{
			memset(sndbuf.mtext,0,128);
			printf("please input message:");
			fgets(sndbuf.mtext,128,stdin);
			msgsnd(msgid,(void *)&sndbuf,strlen(sndbuf.mtext),0);
		}
	}
	else if(pid == 0)//read 100 message
	{
		while(1)
		{
			memset(readbuf.mtext,0,128);
			ret = msgrcv(msgid,(void *)&readbuf,128,100,0);
			printf("type 100 :%s\n",readbuf.mtext);
		}

	}
	return 0;
}

在这里插入图片描述

  • 16
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值