I am LAZY bones? AN ancient AND boring SITE

2009年 06月 09日 的归档

linux进程间通信──消息队列

linux自古以来就是一个多任务多用户的操作系统,所以linux的进程间通信(Inter-Process Communication──IPC)就显得非常重要了。
IPC是一种标准的Unix通讯机制,目前有以下几种通讯方式:管道(Pipe)、信号量(Semaphore)、互斥体(Mutex)、共享内存(Shared Memory)和消息队列(Message Queue),当然也有其他的方式,比如文件系统和dbus等。
今天我就来介绍一种简单实用的进程间通信方式:消息队列(Message Queue)。
首先说说消息队列的优缺点:
1.消息队列只适用于单台主机的进程间通信,如果是不同主机,需要用socket等其他方式,也就不属于IPC的范畴了。
2.消息队列可以实现异步通信,这似乎是优点,但说是它缺点也是可以的:通讯往往不是实时的。
3.消息队列有大小限制,通常只用于小数据量的发送。系统对用户的大小限制可以通过 ulimit -q 命令进行查询。
4.消息队列可以实现阻塞调用和非阻塞调用。
5.实现简单,且可移植性好。

下面通过一个实例来进行说明,以下文件保存成 ipc_msg.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>
 
int main(int argc, char *argv[]){
	int ipc_key,msg_id,msg_len;
	long mtype;
	void * mbuf;
	if(argc==5 && argv[3][0]=='s'){
		ipc_key=atoi(argv[1]);
		mtype=atol(argv[2]);
		msg_len=strlen(argv[4]);
		if ( 0>(msg_id=msgget(ipc_key, 0666|IPC_CREAT)))return 1;
		if ( NULL==(mbuf=malloc(msg_len+sizeof(long)+1)) )return 2;
		memcpy(mbuf, (void *)&mtype, sizeof(long) );
		memcpy(mbuf+sizeof(long), (void *)argv[4], msg_len );
		if ( 0>msgsnd(msg_id, (struct msgbuf *)mbuf, msg_len, 0) )return 3;
		printf("Send Success.n");
	}else if(argc==4 && argv[3][0]=='r'){
		ipc_key=atoi(argv[1]);
		mtype=atol(argv[2]);
		if ( 0>(msg_id=msgget(ipc_key, 0666)))return 1;
		if ( NULL==(mbuf=malloc(4096)) )return 2;
		if ( 0>(msg_len=msgrcv(msg_id,(struct msgbuf *)mbuf, 4000, mtype, IPC_NOWAIT))){
			printf("No message received.n");
			return 3;
		}
		printf("Recv Success.(%d bytes):n",msg_len);
		printf("%sn",(char *)(mbuf+sizeof(long)));
	}else if(argc==3 && argv[2][0]=='c'){
		ipc_key=atoi(argv[1]);
		if ( 0>(msg_id=msgget(ipc_key, 0666)))return 1;
		if ( 0>msgctl(msg_id,IPC_RMID,(struct msqid_ds *)mbuf) )return 2;
	}else{
		printf("usage:"
			"%s key type s message --to send messagen"
			"%s key type r --to receiven"
			"%s key c --to clear queuen"
			,argv[0],argv[0],argv[0]);
	}
	return 0;
}

以上程序,实现了发数据到消息队列和从消息队列收取数据的功能。
第一个参数需要是一个整形数值,表示消息队列的Key;
第二个参数是一个长整形的数值,表示消息的Type,Key+Type 可以唯一确定一个先进先出的消息队列。
第三个参数如果是‘s’则把第四个参数发到指定消息队列,如果是‘r’则从指定消息队列收取消息,并打印。
另外,如果第二个参数是‘c’,则把Key对应的队列删除。
让我们来运行一下试试:

$ gcc -o ipc_msg ipc_msg.c
#编译
$ ipcs -q
 
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
#一开始系统中没有消息队列。
$ ./ipc_msg  1 2 s abc
Send Success.
#发送了一个内容为abc的消息
$ ipcs -q
 
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x00000001 262144     lily       666        3            1           
#发送了一个消息以后,队列里有消息了,key是1,有3个字节。
$ ./ipc_msg  1 2 r
Recv Success.(3 bytes):
abc
#从消息队列成功收到消息了。
$ ipcs -q
 
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x00000001 262144     lily       666        0            0           
#收完以后,空的消息队列仍然存在,不会自动消失。
 
$ ./ipc_msg  1 c
#删除队列
$ ipcs -q
 
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
#成功删除了,回到原始状态。

本文以GNU自由文档许可证发表.