码迷,mamicode.com
首页 > 系统相关 > 详细

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

时间:2015-08-01 23:42:37      阅读:407      评论:0      收藏:0      [点我收藏+]

标签:uc

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   查看消息队列的信息





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

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

标签:uc

原文地址:http://blog.csdn.net/meetings/article/details/47189525

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!