Linux进程间通信-消息队列

消息队列是在两个进程之间传递二进制块数据的一种简单有效的方式。每个数据块都有一个特定的类型,接收方可以根据类型来有选择的接收数据,而不一定像管道和匿名管道那样必须以先进先出的方式接收数据。

Linux消息队列的4个API包括四个系统调用:msgget、msgsnd、msgcrv和msgctl

#include <sys/msg.h>
int msgget( key_t key, int msgflg );
int msgsnd( int sigid, const void* msg_ptr, size_t msg_sz, int msgflg );
int msgrcv( int msqid, void* msg_ptr, size_t msg_sz, long int msgtypes, int msgflg );
int msgctl( int msqid, int command, struct msqid_ds* buf);

l msgget系统调用创建一个消息队列,或者获取一个已有的消息队列。key参数是一个键值,用来标识一个全局唯一的消息队列。msgflg是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。msgget成功时返回一个正整数值,它是消息队列的标识符。msgget失败时返回-1,并设置errno。

l  msgsnd函数用来把消息添加到消息队列中,msqid是由msgget调用返回的消息队列标识符。msg_ptr参数指向一个准备发送的消息,消息必须被定义如下类型:

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

其中,mtype何曾元指定消息的类型,它必须是一个正整数。mtext是消息数据。msg_sz参数是消息的数据部分(mtext)的长度。这个长度可以为0,表示没有消息数据。

msgflg参数控制msgsnd的行为。它通常仅支持IPC_NOWAIT标志,即以非阻塞的方式发送消息。默认情况下,发送消息如果消息队列满了,则msgsnd将阻塞。若IPC_NOWAIT标志被指定,则msgsnd调用可能立即返回并设置errno为EAGAIN。

l  msgrcv函数从消息队列中获取消息,msqid是消息队列标识符,msgp用于存储接收的消息,msgsz指的是消息数据部分的长度。msgtype参数指定接收何种类型的消息,我们可以使用如下几种方式指定消息类型:

msgtype等于0:读取消息队列中的第一个消息。

msgtype大于0:读取消息队列中的第一个类型为msgtype的消息。

msggtype小于0:读取消息队列中第一个类型值比msgtype绝对值小的消息。

msgflag控制msgrcv函数的行为。它可以是如下标志的按位或:

IPC_NOWAIT:如果消息队列中没有消息,则msgrcv调用立即返回并设置errno为ENOMSG。

MSG_CEXEPT:如果msgtype大于0,则接受消息队列中第一个非msgtype类型的消息。

MSG_NOERROR:如果消息数据部分的长度超过了msgsz就将它截断。,

l  msgctl控制消息队列的属性,msgqid是消息队列的标识符。command是将要采取的动作,它可以取3个值

IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。

IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值

IPC_RMID:删除消息队列

buf是指向msgid_ds结构的指针,它指向消息队列模式和访问权限的结构。msgid_ds结构至少包括以下成员:

struct msgid_ds
{
    uid_t shm_perm.uid;
    uid_t shm_perm.gid;
    mode_t shm_perm.mode;
};

成功时返回0,失败时返回-1.

消息队列简单程序示例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/msg.h>
#include <time.h>

#define err_sys(msg) 	do { perror(msg); exit(-1); } while(0)

void msg_stat(int msgid, struct msqid_ds msg_info)
{
	sleep(1);

	if(msgctl(msgid, IPC_STAT, &msg_info) < 0)
		err_sys("msgctl");

	printf("\n");
	printf("msg_cbytes: %ld\n", msg_info.msg_cbytes);
	printf("msg_qnum: %ld\n", msg_info.msg_qnum);
	printf("msg_qbytes: %ld\n", msg_info.msg_qbytes);
	printf("msg_lspid: %d\n", msg_info.msg_lspid);
	printf("msg_lrpid: %d\n", msg_info.msg_lrpid);
	printf("msg_stime: %s\n", ctime(&(msg_info.msg_stime)));
	printf("msg_rtime: %s\n", ctime(&(msg_info.msg_rtime)));
	printf("msg_ctime: %s\n", ctime(&(msg_info.msg_ctime)));
	printf("msg_uid: %d\n", msg_info.msg_perm.uid);
	printf("msg_gid: %d\n", msg_info.msg_perm.gid);
}

struct msgsbuf
{
	int mtype;
	char mtext[1];
}msg_sbuf;
struct msgmbuf
{
	int mtype;
	char mtext[10];
}msg_rbuf;

int main(void)
{
	int msgid;
	struct msqid_ds msg_ginfo;
	pid_t pid;

	msgid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT | IPC_EXCL);
	if(msgid < 0)
		err_sys("msgget");
	//msg_stat(msgid, msg_ginfo);

	if((pid = fork()) < 0)
		err_sys("fork");
	else if(pid == 0)
	{
		sleep(1);
		msg_sbuf.mtype = 10;
		msg_sbuf.mtext[0] = 'a';
		if(msgsnd(msgid, &msg_sbuf, sizeof(msg_sbuf.mtext), IPC_NOWAIT) < 0)
			printf("msgsnd error\n");
		printf("Child: send to msg queue 'a'\n");
		exit(0);
		//msg_stat(msgid, msg_ginfo);
	}
	else
	{
		//sleep(1);
		if(msgrcv(msgid, &msg_rbuf, 4, 10, 0) < 0) /* msgrcv默认是会阻塞的 */
			perror("msgrcv\n");
		else
			printf("Parent: read from msg queue. it is %c.\n", msg_rbuf.mtext[0]);
		printf("Recevied\n");
		//msg_stat(msgid, msg_ginfo);
	}

	waitpid(pid, NULL, 0);
	msgctl(msgid, IPC_RMID, NULL);

	return 0;
}

参考资料:

1、《Linux高性能服务器编程》 第13章 多进程编程/共享内存

2、Linux进程间通信——使用消息队列

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-26 23:18:54

Linux进程间通信-消息队列的相关文章

Linux进程间通信 -- 消息队列 msgget()、msgsend()、msgrcv()、msgctl()

下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信 -- 使用命名管道 一.什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法.  每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构.我们可以通过发送消息来避免命名管道的同步和阻塞问题.但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制. Linux用宏MSGMAX和MSGMNB来限制一条

Linux进程间通信—消息队列

四.消息队列(Message Queue) 消息队列就是消息的一个链表,它允许一个或者多个进程向它写消息,一个或多个进程向它读消息.Linux维护了一个消息队列向量表:msgque,来表示系统中所有的消息队列. 消息队列克服了信号传递信息少,管道只能支持无格式字节流和缓冲区受限的缺点. 消息队列用于运行于同一台机器上的进程间通信,它和管道很相似,是一个在系统内核中用来保存消息的队列,它在系统内核中是以消息链表的形式出现.消息链表中节点的结构用msg声明. 事实上,它是一种正逐渐被淘汰的通信方式,

详解linux进程间通信-消息队列

前言:前面讨论了信号.管道的进程间通信方式,接下来将讨论消息队列. 一.系统V IPC 三种系统V IPC:消息队列.信号量以及共享内存(共享存储器)之间有很多相似之处. 每个内核中的 I P C结构(消息队列.信号量或共享存储段)都用一个非负整数的标识符( i d e n t i f i e r )加以引用. 无论何时创建I P C结构(调用m s g g e t. s e m g e t或s h m g e t) ,都应指定一个关键字(k e y),关键字的数据类型由系统规定为 k e y

Linux 进程间通信 消息队列 实现两个进程间通信

例子: 通过消息队列实现两个进程间通信,一个进程从终端输入数据,通过消息队列发送,另一个进程通过消息队列接收数据 文件1 创建进程1 终端输入通过消息队列发送数据 #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <s

Linux --进程间通信--消息队列

一.消息队列的定义 消息队列能够弥补管道的不足,实现双向交互数据,是一个进程向另一进程发送进程块的方法.与管道不同的是,管道是基于字节流的,消息队列是基于消息的,且消息队列的读取不一定是先进先出. 二.消息队列的创建 通过函数int messget(key_t key,int msgflg);创建 key:端口号,可以有 ftok生成. msgflg: IPC_CRTAT 若果 IPC不存在,则创建一个IPC资源, IPC_EXCL:一般和 IPC_CREAT一起使用可以保证所得的对象是新建的,

进程间通信——消息队列

1.消息队列的简介 消息队列就是在进程之间架设起通信的通道,信息在通道中传递(具有时间先后的),从宏观逻辑上来讲与管道是一致的.即就是消息队列也同样是:(1).具有入口和出口:(2).消息从入口到出口,是FIFO的:(3).所以消息在其中是队列的存储形式. 消息队列与管道不同的地方在于:管道中的数据并没有分割为一个一个的数据独立单位,在字节流上是连续的.然而,消息队列却将数据分成了一个一个独立的数据单位,每一个数据单位被称为消息体.每一个消息体都是固定大小的存储块儿,在字节流上是不连续的. 2.

linux程序设计——消息队列(第十四章)

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

XSI进程间通信-----消息队列

1. 基本特点 1) 消息队列是一个由系统内核负责存储和管理,并通过消息队列标识引用的数据链表,消息队列 和有名管道fifo的区别在: 后者一次只能放一个包,而前者则可以放很多包,这样就能处理发包快,哪包慢的问题 2) 可以通过msgget函数创建一个新的消息队列, 或获取一个已有的消息队列. 通过msgsnd函数 (send)向消息队列的后端追加消息, 通过msgrcv(receive)函数从消息队列的前端提取消息. 3) 消息队列中的每个消息单元除包含消息数据外,还包含消息类型和数据长度.消

进程间通信-----消息队列

消息队列(报文队列):两个进程间通过发送数据块的形式进行通信.一个进程把需要发送的消息通过一个函数发送到消息队列中,另一个进程再从消息队列中读取该消息. 函数: # include <sys/types.h> # include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id); //生成下面函数的key.可认为是一个端口号 int msgget(key_t key, int msgflg);//创建消息队列,返回消