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

1. 基本特点

1) 消息队列是一个由系统内核负责存储和管理,并通过消息队列标识引用的数据链表,消息队列 和有名管道fifo的区别在: 后者一次只能放一个包,而前者则可以放很多包,这样就能处理发包快,哪包慢的问题

2) 可以通过msgget函数创建一个新的消息队列, 或获取一个已有的消息队列。 通过msgsnd函数 (send)向消息队列的后端追加消息, 通过msgrcv(receive)函数从消息队列的前端提取消息。

3) 消息队列中的每个消息单元除包含消息数据外,还包含消息类型和数据长度。消息类型的存在意义:同一个消息队列处理不同类型的消息,比如现在处理存款和取款两种情况,我们就可以定义两种类型的数据而不是定义两条消息队列

4) 内核为每个消息队列,维护一个msqid_ds结构体形式的消息队列对象。

truct msqid_ds {
    struct ipc_perm msg_perm;     // 权限信息
    time_t          msg_stime;    // 随后发送时间
    time_t          msg_rtime;    // 最后接收时间
    time_t          msg_ctime;    // 最后改变时间
    unsigned long   __msg_cbytes; // 消息队列中的字节数
    msgqnum_t       msg_qnum;     // 消息队列中的消息数
    msglen_t        msg_qbytes;   // 消息队列能容纳的最大字节数
    pid_t           msg_lspid;    // 最后发送进程PID
    pid_t           msg_lrpid;    // 最后接收进程PID
};
struct ipc_perm {
    key_t          __key; // 键值
    uid_t          uid;   // 有效属主ID
    gid_t          gid;   // 有效属组ID
    uid_t          cuid;  // 有效创建者ID
    gid_t          cgid;  // 有效创建组ID
    unsigned short mode;  // 权限字
    unsigned short __seq; // 序列号
};

2. 常用函数

头文件 :  #include <sys/msg.h>

1) 创建/获取消息队列

int msgget (key_t key, int msgflg);

A. 该函数以key参数为键值创建消息队列,或获取已有的消息队列。

B. msgflg取值:

0         - 获取,不存在即失败。

IPC_CREAT - 创建,不存在即创建,已存在即获取,除非...

IPC_EXCL  - 排斥,已存在即失败。

C. 成功返回消息队列标识msqid,失败返回-1。

2) 向消息队列发送消息

int msgsnd (int msqid, const void* msgp,size_t msgsz, int msgflg);

A. msgp参数指向一个包含消息类型和消息数据的内存块。该内存块的前4个字节必须是一个大于0的整数,代表消息类型,其后紧跟消息数据。消息数据的字节长度用msgsz参数表示。

注意:msgsz参数并不包含消息类型的字节数(4)。

B. 若内核中的消息队列缓冲区有足够的空闲空间(由内核参数设定),则此函数会将消息拷入该缓冲区并立即返回0,表示发送成功,否则此函数会阻塞,直到内核中的消息队列缓冲区有足够的空闲空间为止

C. 若msgflg参数包含IPC_NOWAIT位, 则当内核中的消息队列缓冲区没有足够的空闲空间时, 此函数不会阻塞,而是返回-1,errno为EAGAIN。

D. 成功返回0,失败返回-1。

3) 从消息队列接收消息

ssize_t msgrcv (int msqid, void* msgp, size_t msgsz,long msgtyp, int msgflg);

A. msgp参数指向一个包含消息类型(4字节),和消息数据的内存块.

B. 若所接收到的消息数据字节数大于msgsz参数,即消息太长,且msgflg参数包含MSG_NOERROR位,则该消息被截取msgsz字节返回,剩余部分被丢弃。

C. 若msgflg参数不包含MSG_NOERROR位,消息又太长,则不对该消息做任何处理,直接返回-1。

D. msgtyp参数表示期望接收哪类消息:10和20(注意:msgtype参数并不包含消息类型的字节数(4)。)

=0 - 返回消息队列中的第一条消息。

>0 - 若msgflg参数不包含MSG_EXCEPT位,则返回消息队列中第一个类型为msgtyp的消息;若msgflg参数包含MSG_EXCEPT位,则返回消息队列中第一个类型不为msgtyp的消息。

<0 - 返回消息队列中类型小于等于msgtyp的绝对值的消息。若有多个,则取类型最小者。

E. 若消息队列中有可接收消息,则此函数会将该消息移出消息队列并立即返回0, 表示接收成功,否则此函数会阻塞,直到消息队列中有可接收消息为止。

F. 若msgflg参数包含IPC_NOWAIT位,则当消息队列中没有可接收消息时,此函数不会阻塞, 而是返回-1,errno为ENOMSG。

G. 成功返回所接收到的消息数据的字节数,失败返回-1。

4) 销毁/控制消息队列

int msgctl (int msqid, int cmd, struct msqid_ds* buf);

A. cmd取值:

IPC_STAT - 获取消息队列的属性,通过buf参数输出。

IPC_RMID - 立即删除消息队列。此时所有阻塞在对该消息队列的,msgsnd和msgrcv函数调用,都会立即返回失败errno为EIDRM。

IPC_SET  - 设置消息队列的属性,通过buf参数输入,仅有四个属性可设置

B. 成功返回0,失败返回-1。

3. 编程模型

#include <stdio.h>
#include <string.h>
#include <sys/msg.h>

int main (void) {
	printf ("创建消息队列...\n");

	key_t key = ftok (".", 100);
	if (key == -1) {
		perror ("ftok");
		return -1;
	}

	int msqid = msgget (key, 0644 | IPC_CREAT | IPC_EXCL);
	if (msqid == -1) {
		perror ("msqget");
		return -1;
	}

	printf ("向消息队列(0x%08x/%d)发送数据...\n", key, msqid);

	for (;;) {
		printf ("> ");

		struct {
			long mtype;
			char mtext[1024];
		}	msgbuf = {1234, ""};
		gets (msgbuf.mtext);

		if (! strcmp (msgbuf.mtext, "!"))
			break;

		if (msgsnd (msqid, &msgbuf, (strlen (msgbuf.mtext) + 1) *
			sizeof (msgbuf.mtext[0]), 0) == -1) {
			perror ("msgsnd");
			return -1;
		}
	}

	printf ("销毁消息队列(0x%08x/%d)...\n", key, msqid);

	if (msgctl (msqid, IPC_RMID, NULL) == -1) {
		perror ("msgctl");
		return -1;
	}
	printf ("大功告成!\n");
	return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/msg.h>

int main (void) {
	printf ("获取消息队列...\n");

	key_t key = ftok (".", 100);
	if (key == -1) {
		perror ("ftok");
		return -1;
	}

	int msqid = msgget (key, 0);
	if (msqid == -1) {
		perror ("msgget");
		return -1;
	}

	printf ("从消息队列(0x%08x/%d)接收消息...\n", key, msqid);

	for (;;) {
		struct {
			long mtype;
			char mtext[1024];
		}	msgbuf = {};

		ssize_t msgsz = msgrcv (msqid, &msgbuf,
			sizeof (msgbuf.mtext) - sizeof (msgbuf.mtext[0]), 1234,
			MSG_NOERROR/* | IPC_NOWAIT*/);
		if (msgsz == -1)
			if (errno == EIDRM) {
				printf ("消息队列(0x%08x/%d)已销毁!\n", key, msqid);
				break;
			}
			else
			if (errno == ENOMSG) {
				printf ("现在没有消息,干点儿别的...\n");
				sleep (1);
			}
			else {
				perror ("msgrcv");
				return -1;
			}
		else
			printf ("%04d< %s\n", msgsz, msgbuf.mtext);
	}
	printf ("大功告成!\n");
	return 0;
}

命令: ipcs -q   查看消息队列的信息

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

时间: 2024-10-10 23:20:02

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

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

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

进程间通信——消息队列

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

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,

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一起使用可以保证所得的对象是新建的,

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

消息队列(报文队列):两个进程间通过发送数据块的形式进行通信.一个进程把需要发送的消息通过一个函数发送到消息队列中,另一个进程再从消息队列中读取该消息. 函数: # 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);//创建消息队列,返回消

进程间通信IPC:消息队列,信号量,共享内存

2015.3.4星期三 阴天 进程间通信:IPC 文件对象:记录文件描述符,文件开关等 IPC标示符:系统全局的流水号两个进程要通信,打开的是唯一的对象进行通讯,通过key操作 XSI IPC:消息队列,信号量,共享内存. ipcs 查看ip对象共享内存,信号量,消息队列等信息ipcrm 删除一个IP对象 Linux为用户提供了完善的,强大的网络功能完善的内置网络:其他操作系统不包含如此紧密的和内核结合在一起的网络部分 共享内存标示符的获取有两种方法:ftok(pathname,id)另一个是K