首页 > 系统相关 >Linux学习记录(十一)———进程间的通信(消息队列)

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

时间:2024-08-19 14:24:24浏览次数:10  
标签:十一 队列 msgid int 消息 key Linux include

文章目录


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;
}

在这里插入图片描述

标签:十一,队列,msgid,int,消息,key,Linux,include
From: https://blog.csdn.net/qq_63556165/article/details/141324403

相关文章

  • linux第一宏
    在ubuntu内下载源代码并找到宏源码vim-toffsetof987#ifndefoffsetof988#defineoffsetof(typ,memb)((unsignedlong)((char*)&(((typ*)0)->memb)))989#endifvim-tcontainer_of240/**241*Returnsapointertothecontainerofthislistelement.......
  • Linux下的库(静态与动态)原理与制作
    程序的编译过程程序的编译过程是将源代码转换为可执行文件的一系列步骤。这个过程通常包括预处理、编译、汇编和链接等阶段 1.预处理(Preprocessing)预处理器(cpp)处理源代码文件中的预处理指令,如#include和#define。它展开宏定义,包含头文件,并删除注释。输出是经过预处理的......
  • Java轻松实现跨平台(Windows、Linux)多协议(Twain、Sane)的Web扫描
     由于项目需要,开发在Windows下与Linux下扫描功能,Linux主要是信创的两个系统(UOS、麒麟),研究了一下发现,Windows使用Twain协议与扫描仪通讯,Linux使用的是Sane协议与扫描仪通讯,找到Twain协议和Sane协议的标准文档,英文的,都有大几百页,项目一个月内要求上线,明显没时间慢慢研究,于......
  • linux 安装python
    1、先查看系统python所在位置[root@localhost~]#whereispythonpython:/usr/bin/python/usr/bin/python2.7/usr/lib/python2.7/usr/lib64/python2.7/etc/python/usr/include/python2.7可确认系统原python环境在/usr/bin/下。2、进入/usr/bin/cd/usr/bin/3、先安......
  • 【~Linux系统性能调优技巧~】
    ......
  • 【Linux入门】DHCP与FTP原理及其配置实例
    文章目录DHCP原理一、DHCP概述二、DHCP的工作原理三、DHCP的分配方式四、DHCP的租约五、DHCP的应用场景FTP原理一、FTP概述二、FTP的工作原理三、FTP的连接模式四、FTP的应用配置实例DHCP配置实例DHCP服务器配置(CentOS7)1.环境准备2.安装DHCP服务3.配置网络接口4.......
  • Linux安装nginx1.26.2
    第一步:去官网下载指定的版本http://nginx.org/en/download.html第二步:解压压缩包:tar-zxvf  ......tar.gz第三步:编译nginx ./configure如果出现报错:./configure:error:theHTTPgzipmodulerequiresthezliblibrary.Youcaneitherdisablethemodulebyusing--......
  • java队列
    1.队列定义:在Java中,队列(Queue)是一种常用的数据结构,属于java.util包。Queue接口继承自Collection接口,定义了一些基本操作,如入队、出队、查看队列头部等。Java提供了多种实现Queue接口的类,这些类可以满足不同的使用需求。2.Java队列的常见实现LinkedList:实现了Que......
  • Linux C++ 开发4 - 入门makefile一篇文章就够了
    1.make和Makefile1.1.什么是make?1.2.什么是Makefile?1.3.make与Makefile的关系2.Makefile的语法2.1.基本语法2.2.变量2.3.伪目标2.4.模式规则2.5.自动变量2.6.条件判断3.示例演示3.1.编译HelloWorld程序3.2.编译多文件项目3.2.1.项目......
  • python subprocess 执行Linux指令
    一、subprocess模块1、概述subprocess模块首先推荐使用的是它的run方法subprocess.run(),更高级的用法可以直接使用Popen接口subprocess.Popen()。2、优点安全性:与os.system相比,subprocess避免了shell注入攻击的风险。灵活性:subprocess可以与子进程的stdin、stdout和std......