IPC通信_消息队列

(共享内存,信号量,消息队列等方式时,有System v以及POXIS两种接口类型,这里介绍常用的systemV接口)

内核中的IPC结构(共享内存,信号量,消息队列)都用一个非法整数的标识符(identifier)加以引用。这里的标识符(identifier)是IPC对象的内部名。

为了使多个合作进程能够在同一IPC对象上汇聚,提供一个该IPC对象的外部名键(key),每一个IPC对象都与一个键(key)相关联。

消息队列是消息的链接表,存储在内核中,有消息队列标识符标识。下面描述几个涉及到的API。

函数1:

#include <sys/ipc.h>
key_t ftok(const char* path, int id); 

  该函数的作用就是由一个路径名和项目ID产生一个键。

返回值   : 成功返回键值(key),失败返回-1

参数path:必须是一个存在的文件或者目录,ftok会根据文件inode在系统内的唯一性取一 个值,再结合第二个参数的低8位合成key

参数id    :项目ID,是一个0~255之间的字符值,自己约定即可

函数2:

#include <sys/msg.h>
int msgget(key_t key, int flag);

  该函数的作用是打开一个现有的队列或创建一个新队列,返回队列ID(就是标识符)。

返回值 :成功返回队列ID,失败返回-1

参数key:  键值

参数flag:  设置的权限,设置下表权限(消息队列和共享内存术语“读”和“写”,信号量术语“读”和“更改”),且必须指定IPC_CREAT和IPC_EXCL位(例如:IPC_CREAT |0666)


权限



用户读

用户写(更改)


0400

0200


组读

组写(更改)


0040

0020


其他读

其他写(更改)


0004

0002


IPC_CREAT只置此位


不管是否已存在该消息队列,则都返回该消息队列ID,若不存在则创建消息队列


IPC_EXCL 只置此位


不管有没有该消息队列,msgget()都返回-1


IPC_CREAT|IPC_EXCL 都置位


如果没有该块消息队列,则创建,并返回消息队列ID。若已有该消息队列,则返回-1 


函数3:

#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

  该函数对队列执行多种操作。

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

参数msqid: 队列ID

参数cmd   : 指定对msqid队列要执行的命令,见下表


IPC_STAT


取此队列的msqid_ds结构,并将它存放在buf指向的结构中


IPC_SET


将字段msg_perm.uid、msg_perm.gid、msg_perm.mode和msg_qbytes从buf指向的结构复制到与这个队列相关的msqid_ds结构中。此命令只能有下列两种进程执行:

1、该进程有效用户ID等于msg_perm.cuid或msg_perm.uid

2、该进程具有超级用户特权,只有超级用户才能增加msg_gbytes值


IPC_RMID


从系统中删除该消息队列以及仍在该队列中的所有数据。这种删除立即生效。仍在使用这一消息队列的其他进程在它们下一次试图对此队列进行操作时,将得到EIDRM错误。此命令只能有下列两种进程执行:

1、该进程有效用户ID等于msg_perm.cuid或msg_perm.uid

2、该进程具有超级用户特权

参数buf : 每个队列都有与此队列相关的msqid_ds结构体,结构体如下

struct msqid_ds

{

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 */

};

函数4:

#include <sys/msg.h>
int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);

  发送数据的函数

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

参数msqid: 队列ID

参数 ptr: 指针ptr指向一个长整型数的消息类型,其后紧跟消息数据。可定义下列结构体

struct mymesg

{

long mtype; //消息类型

char mtext[512];  //长度为512的数据

}

参数nbytes: 上面结构体中mtext的长度

参数flag:模式设置,可以设置为IPC_NOWAIT, 非阻塞标志。

当msgsnd返回成功时,消息队列相关的msgid_ds结构会随之更新,表明调用的进程ID(msg_lspid)、调用的时间(msg_stime)以及队列中新增的消息(msg_qnum)。

函数5:

#include <sys/msg.h>
int msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);

  接受数据的函数

返回值       :成功返回消息数据的长度,失败返回-1

参数msqid :队列ID

参数ptr      : 同发送函数一样

参数nbytes:同接受函数一样,指定缓冲区长度,如果消息长度超过nbytes,且flag中设置了 MSG_NOERROR位,则 该消息会被截断。

参数type    : 指定想要哪一种消息


type == 0


返回队列中的第一个消息


type > 0


返回队列中消息类型为type的第一个消息


type < 0


返回队列中消息类型值小于等于type绝对值的消息,如果有若干个此类消息,则取类型值最小的消息

参数flag     : 同接受函数

msgrcv成功执行后,内核会更新与该消息队列相关联的msgid_ds结构,以指示调用者的进程ID(msg_lrpid)和调用时间(msg_rtime),并指示队列中的消息数减少了1个(msg_qnum)。

举例:一个进程发送两种消息,另外两个进程分别接受这两个消息。

1、msgSend.cpp

#include <sys/types.h>
#include <sys/msg.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <iostream>
#define MSG1 1
#define MSG2 2
#define BUFSIZE 48
struct mybuf
{
	long mytype;
	char msgtext[BUFSIZE];
}msg;
int main()
{
	key_t key = ftok("/tmp/",1);//获取键值
	if(key == -1)
	{
		printf("ftok failed\n");
		return -1;
	}
	//获取ID
	int msgid = msgget(key,IPC_CREAT |0666);
	if(msgid == -1)
	{
		printf("msgget failed\n");
		return -1;
	}
	int msgType =0;
	std::string str;
	while(std::cin>>msgType>>str)
	{
		if(msgType == MSG1)
		{
			msg.mytype = MSG1;
			memset(msg.msgtext,0,BUFSIZE);
			strncpy(msg.msgtext, str.c_str(),BUFSIZE);
			if(msgsnd(msgid, &msg, str.size(), 0) == -1)
			{//发送失败
				printf("msgsnd failed\n");
				return -1;
			}
		}
		else if(msgType == MSG2)
		{
			msg.mytype = MSG2;
			memset(msg.msgtext,0,BUFSIZE);
			strncpy(msg.msgtext, str.c_str(),BUFSIZE);
			if(msgsnd(msgid, &msg, str.size(), 0) == -1)
			{//发送失败
				printf("msgsnd failed\n");
				return -1;
			}
		}	

		sleep(2);
	}
	return 0;
}

 2、msgRcv1.cpp

 1 #include <sys/types.h>
 2 #include <sys/msg.h>
 3 #include <unistd.h>
 4 #include <stdio.h>
 5 #include <fcntl.h>
 6 #include <string.h>
 7 #include <iostream>
 8 #define MSG1 1
 9 #define MSG2 2
10 #define BUFSIZE 48
11 struct mybuf
12 {
13     long mytype;
14     char msgtext[BUFSIZE];
15 }msg;
16 int main()
17 {
18     key_t key = ftok("/tmp/",1);
19     if(key == -1)
20     {
21         printf("ftok failed\n");
22         return -1;
23     }
24     int msgid = msgget(key,IPC_CREAT |0666);
25     if(msgid == -1)
26     {
27         printf("msgget failed");
28         return -1;
29     }
30     while(1)
31     {
32         if(msgrcv(msgid, &msg, BUFSIZE, MSG1, 0) == -1)                                    //接受失败
33         {
34             printf("recive is failure\n");
35             return -1;
36         }
37         printf(" rcv1:%s\n", msg.msgtext);
38     }
39     printf("rcv end\n");
40     return 0;
41 }
42     

3、msgRcv2.cpp

 1 #include <sys/types.h>
 2 #include <sys/msg.h>
 3 #include <unistd.h>
 4 #include <stdio.h>
 5 #include <fcntl.h>
 6 #include <string.h>
 7 #include <iostream>
 8 #define MSG1 1
 9 #define MSG2 2
10 #define BUFSIZE 48
11 struct mybuf
12 {
13     long mytype;
14     char msgtext[BUFSIZE];
15 }msg;
16 int main()
17 {
18     key_t key = ftok("/tmp/",1);
19     if(key == -1)
20     {
21         printf("ftok failed\n");
22         return -1;
23     }
24     int msgid = msgget(key,IPC_CREAT |0666);
25     if(msgid == -1)
26     {
27         printf("msgget failed");
28         return -1;
29     }
30     while(1)
31     {
32         if(msgrcv(msgid, &msg, BUFSIZE, MSG2, 0) == -1)                                    //接受失败
33         {
34             printf("recive is failure\n");
35             return -1;
36         }
37         printf(" rcv2:%s\n", msg.msgtext);
38     }
39     printf("rcv end\n");
40     return 0;
41 }
42     

原文地址:https://www.cnblogs.com/ho966/p/12257562.html

时间: 2024-08-09 10:45:21

IPC通信_消息队列的相关文章

IPC通信之消息队列、信号量和共享内存

有三种IPC我们称作XSI IPC,即消息队列,信号量以及共享存储器.XSI IPC源自System V的IPC功能.由于XSI IPC不使用文件系统的命名空间,而是构造了它们自己的名字空间,为此常常受到批评. 相似之处:每个内核中的IPC结构都用一个非负整数的标识符加以引用.例如对一个消息队列发送或取消息,只需要知道其队列标识符.与文件标识符不同,IPC标识符不是小的整数,当一个IPC结构被创建,以后又被删除时,与这种结构相关的标识符连续加1,直至达到一个整形数的最大正值,然后又回转到0. 标

linux_c 开发(5-5)进程间通讯_消息队列

进程间通讯_消息队列 定义: UNIX早起通信机制之一的信号能够传送的信息量有限,管道则只能传送无格式的字节流,这无疑会给应用程序开发带来不便.消息队列(也称报文队列)则克服了这些缺点. 发展: 消息队列就是一个消息的链表.可以把消息看做一个记录,**具有特定的格式.进程可以向中按照一定的规则添加新消息:另一些进程则可以从消息队列中读取消息. 分类: 目前主要有两种类型的消息队列:POSIX消息队列 以及系统V消息队列,系统V消息队列目前被大量使用. 持续性:系统V消息队列是随内核持续的,只有在

进程间通信---IPC对象 之 消息队列

IPC对象,既我们所说的进程间通信,下面就来总结一下都有哪些方式以及怎么使用. 一 消息队列 1 消息队列的创建: int msgget(key_t key, int msgflg); 功能:获取指定的key值的消息队列ID 参数: @key <1>IPC_PRIVATE:每次都会创建一个新的消息队列 [用在亲缘关系的进程间痛惜] <2>ftok函数获的key [用在非亲缘关系进程间通信] key_t ftok(const char *pathname, int proj_id);

Linux程序设计学习笔记----System V进程通信之消息队列

一个或多个进程可向消息队列写入消息,而一个或多个进程可从消息队列中读取消息,这种进程间通讯机制通常使用在客户/服务器模型中,客户向服务器发送请求消息,服务器读取消息并执行相应请求.在许多微内核结构的操作系统中,内核和各组件之间的基本通讯方式就是消息队列.例如,在 MINIX 操作系统中,内核.I/O 任务.服务器进程和用户进程之间就是通过消息队列实现通讯的. Linux中的消息可以被描述成在内核地址空间的一个内部链表,每一个消息队列由一个IPC的标识号唯一的标识.Linux 为系统中所有的消息队

IPC(SystemV) 之 消息队列

本文介绍最后一个SystemV的IPC,即消息队列.消息队列提供了一个从一个进程向另外一个进程发送消息的方式.而且每个数据块都被认为包含一个类型,所以接收进程可以独立的接收含有不同类型的数据块.在实际的使用中,还是要结合使用场景来决定是否使用消息队列.我遇到过的场景就是进程之间需要有序的去共享具有类型的消息.除此之外我也提供不了一个更贴切的使用场景,可能大多数人喜欢用Unix域套接字或者共享内存来代替这种方式. 下面详细介绍一下共享内存. 首先是头文件,和另外两个IPC类似,消息队列的头文件是<

进程间通信(IPC)之————消息队列

一.消息队列 前面提到的进程间通信的一种最基本的方式就是管道,而现在来谈一下另一种进程间的通信方式--消息队列.消息队列是从一个进程向另一个进程发送数据块的方式,每个数据块都有其类型,接收者接收的数据块也可以有不同的类型,这样我们就可以通过发送消息的方式来避免命名管道的同步和阻塞问题. 消息队列不同于管道的是,管道是基于字节流的,而消息队列是基于消息的,而且消息队列的读取方式不一定是先进先出的,消息队列是用链表实现的:但相同的是,它们有一样的不足,就是都有固定的大小,每个消息的大小都有上限(ms

Linux:进程通信之消息队列Message实例

/*send.c*/ /*send.c*/ #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <errno.h> #define MSGKEY 1024 struct msgstru { long msgtype; char msgtext[2048]; }; main() { struct msgstru ms

第15章 进程间通行 15.6 XSI IPC 15.7 消息队列

15.6 XSI IPC (1)3种称作XSI IPC的IPC是: 1)消息队列 2)信号量 3)共享存储器 (2)标识符和键 1)标识符:是一个非负整数,用于引用IPC结构.是IPC对象的内部名. 2)键:IPC对象的外部名.可使多个合作进程能够在同一IPC对象上汇聚. (3)IPC_PRIVATE键: 用于创建一个新的IPC结构.不能指定此键来引用一个现有的IPC结构. (4)ftok函数: 由一个路径名和项目ID产生一个键. (5)ipc_perm结构体 规定了ipc结构的权限和所有者.

linux进程间的通信(C): 消息队列

一.消息队列(message queue) 消息队列也是System V IPC机制之一. 消息队列与命名管道类似, 但少了打开和关闭管道方面的复杂性. 但使用消息队列并未解决我们在使用命名管道时遇到的一些问题, 如管道满时的阻塞问题. 消息队列提供了一种在两个不相关进程间传递数据的简单有效的方法. 与命名管道相比, 消息队列的优势在于,它独立于发送和接收进程而存在, 这消除了在同步命名管道的打开和关闭时可能产生的一些困难. 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法. 而且,