关闭

进程间通信之消息队列

标签: linuxCIPC消息队列进程间通信
401人阅读 评论(0) 收藏 举报
分类:

何为消息队列

消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值。我们可以通过发送消息来避免命名管道的同步和阻塞问题。消息队列与管道不同的是,消息队列是基于消息的,而管道是基于字节流的,且消息队列的读取不一定是先入先出。消息队列与命名管道有一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)。

函数原型

创建一个消息队列:

         

其中的key一般通过ftok函数来得到(也可以认为是一个端口号),msgflg则与具体的创建方法和权限有关,单独的IPC_CREAT表示如果这个消息队列不存在,则创建;存在则打开。 IPC_CREAT | IPC_EXCL表示如果不存在,则创建,存在则出错返回,此举是为了创建一个全新的消息队列。

消息队列创建好后,可以通过命令行的方式来查看:ipcs -q

       

也可以通过命令行删除它:ipcrm -q  key值(或msqid)

         

当然也可以在程序中删除,要借助msgctl函数:

        

msqid当然是想要删除的消息队列id了,cmd可以传IPC_RMID表示通过msqid来删除,buf用来存储获取自消息队列的一些数据,这里只用到了删除,那么设为NULL即可。

还有msgsnd(发送消息)与msgrcv(接收消息)方法:

        

msgp是一个结构体,有些系统实现了,有些需要我们自己定义:             

         

mtype用以区分消息类型,因为不同的进程把各自的消息都扔进同一个消息队列,想要取出来自己需要的消息,就需要这个mtype来区分了。mtext是存放数据的数组,大小可以自定义。msgsz就指定了mtext的大小。msgflg用来设置相关的一些模式,这里直接传0,表示以阻塞方式发送(或接收)。

举个栗子

comm.c:封装了消息缓冲队列函数的创建,销毁,发送与接收,用以被server和client调用

#include "comm.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int cli_type = 1;
int ser_type = 2;


static int comm_msg(int flag)
{
	int key = ftok(_PATH_NAME_, _PROJ_ID_);	
	if (key < 0)
	{
		perror("ftok");
		exit(1);
	}
	
	int id = msgget(key, flag);
	if (id < 0)
	{
		perror("msgget");
		exit(2);
	}
	
	return id;
}

int create_msg()
{
	int flag = IPC_CREAT | IPC_EXCL | 0666; 
	return comm_msg(flag);
}

int get_msg()
{
	int flag = IPC_CREAT; 
	return comm_msg(flag);
}

int send_msg(int id, char *buf, int type)
{
	struct msgbuf msg;
	msg.mtype = type;
	strncpy(msg.mtext, buf, strlen(buf)+1);

	int ret = msgsnd(id, &msg, sizeof(msg.mtext), 0);	// 0缺省阻塞
	if (ret < 0)
	{
		perror("msgsnd");
		return ret;
	}
	return 0;
}


int recv_msg(int id, char *buf_out, int type)
{
	struct msgbuf msg;
	size_t _s = msgrcv(id, &msg, sizeof(msg.mtext), type, 0);
	if (_s < 0)
	{
		perror("msgrcv");
		return _s;
	}
	strcpy(buf_out, msg.mtext);
}	

int destory_msg(int id)
{
	msgctl(id, IPC_RMID, NULL);
}

comm.h:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define _PATH_NAME_ "./comm/comm.h"
#define _PROJ_ID_ 0x111
#define _SIZE_ 1024

extern int ser_type;
extern int cli_type;


struct msgbuf
{
	long mtype;
	char mtext[_SIZE_];
};

int create_msg();
int get_msg();
int send_msg(int id, char *buf, int type);
int recv_msg(int id, char *buf_out, int type);
int destory_msg(int id);

server.c:

#include <stdio.h>
#include "comm/comm.h"
#include <unistd.h>
#include <string.h>

int main()
{
	int id = create_msg();
	printf("%d\n", id);

	char buf[_SIZE_];
	while (1)
	{
		memset(buf, 0, sizeof(buf));

		recv_msg(id, buf, cli_type);
		printf("client# %s\n", buf);
		if (strcasecmp(buf, "quit") == 0)
			break;

		memset(buf, 0, sizeof(buf));
		printf("Please Enter# ");
		fflush(stdout);
		ssize_t _s = read(0, buf, sizeof(buf));
		if (_s > 0)
		{
			buf[_s - 1] = 0;
		}
		send_msg(id, buf, ser_type);
	}

	destory_msg(id);

	return 0;
}

client.c:

#include <stdio.h>
#include "comm/comm.h"
#include <unistd.h>
#include <string.h>

int main()
{
	int id = get_msg();
	printf("%d\n", id);

	char buf[_SIZE_];
	while (1)
	{
		memset(buf, 0, sizeof(buf));
		printf("Please Enter# ");
		fflush(stdout);
		ssize_t _s = read(0, buf, sizeof(buf));
		if (_s > 0)
		{
			buf[_s - 1] = 0;
		}
		send_msg(id, buf, cli_type);
		if (strcasecmp(buf, "quit") == 0)
			break;

		memset(buf, 0, sizeof(buf));
		recv_msg(id, buf, ser_type);
		printf("server# %s\n", buf);

	}

	return 0;
}

运行示例:

         

消息队列的特点

  1. 面向数据块的服务
  2. 相对于管道而言函数复杂
  3. 生命周期随内核(不主动删除不会自动释放)
  4. System V版本的消息队列,由操作系统在底层提供队列支持。消息条数,消息大小,整个系统中的消息队列数有限制
1
0
查看评论

进程间通信方式之消息队列

消息队列进行通信的一些操作: 1、使用msgget()函数创建打开队列; 2、使用msgrcv()函数从队列中读数据; 3、使用msgsnd()函数写数据到队列中; 4、使用msgctl()函数控制消息队列。 以下是消息队列中使用到的一些函数: 1、msgget   ...
  • Echo_Ana
  • Echo_Ana
  • 2016-10-23 21:56
  • 1176

进程间通信系列 之 消息队列应用实例

进程间通信(IPC,Interprocess communication)是一组编程接口,让程序员能够协调不同的进程,使之能在一个操作系统里同时运行,并相互传递、交换信息。这使得一个程序能够在同一时间里处理许多用户的要求。因为即使只有一个用户发出要求,也可能导致一个操作系统中多个进程的运行,进程之间...
  • iamonlyme
  • iamonlyme
  • 2013-11-13 08:33
  • 1911

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

今天我们来介绍一下如何使用消息队列来进行进程间通信。1、消息队列消息队列是由内核维护的一种链式结构。链表中每一个记录又称作消息,消息具有特定的格式和优先级别。各个进程通过消息队列标识符来引用消息队列,这样,写进程叫可以按照一定的规则添加新的消息,读进程可以按一定的规则取走消息(具体按什么规则我们稍后...
  • Xiejingfa
  • Xiejingfa
  • 2016-03-19 15:37
  • 1237

进程间通信方式总结——消息队列

Linux/Unix系统IPC是各种进程间通信方式的统称,但是其中极少能在所有Linux/Unix系统实现中进行移植。随着POSIX和Open Group(X/Open)标准化的推进呵护影响的扩大,情况虽已得到改善,但差别仍然存在。一般来说,Linux/Unix常见的进程间通信方式有:管道、消息...
  • tf_apologize
  • tf_apologize
  • 2017-04-16 11:52
  • 651

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

面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处。有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信——使用命名管道 一、什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。  每个数据块都被认为含有一个类...
  • zhanghuaichao
  • zhanghuaichao
  • 2016-11-20 17:07
  • 781

Linux进程间通信——消息队列应用实例

消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。下面是两个测试模块 接收模块 msgreceive.c 的代码...
  • li_wen01
  • li_wen01
  • 2017-01-20 17:26
  • 436

Linux系统编程——进程间通信:消息队列

消息队列提供了一种在两个不相关的进程之间传递数据的简单高效的方法。对于消息队列的操作,我们可以类比为这么一个过程:假如 A 有个东西要给 B,因为某些原因 A 不能当面直接给 B,这时候他们需要借助第三方托管(如银行),A 找到某个具体地址的建设银行,然后把东西放到某个保险柜里(如 1 号保险柜),...
  • tennysonsky
  • tennysonsky
  • 2015-06-02 20:45
  • 88784

linux 进程间通信三 消息队列以及实例

代码来自:嵌入式linux应用开发标准教程 消息可以理解为写信给某个人,这里在应用中是告诉系统写信人和写信的内容就可以了, 别人会来看发信人是谁,如果不是自己想要的就放弃读信或者只要有消息自己就读取消息 消息队列就是按队列的方式处理很多消息,先发的最先被读 消息队列: ht...
  • liang890319
  • liang890319
  • 2012-12-11 09:40
  • 5620

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

下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处。 一、什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。  每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同...
  • ljianhui
  • ljianhui
  • 2013-08-25 00:09
  • 100994

进程间通信--消息队列

进程间通信:每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据走,内核提供的这种机制称为进程间通信。 通信分类:匿名管道,命名管道,消息队列,信号量...
  • L_XRUI
  • L_XRUI
  • 2017-05-17 00:05
  • 983
    个人资料
    • 访问:92276次
    • 积分:2117
    • 等级:
    • 排名:千里之外
    • 原创:108篇
    • 转载:17篇
    • 译文:0篇
    • 评论:16条
    文章分类
    最新评论