Linux进程间通讯|消息队列

消息队列

1. 消息队列概述

消息队列就是一些消息的列表,用户可以在消息队列中添加消息和读取消息等。消息队列具有一定的FIFO特性,但是它可以实现消息的随机查询,比FIFO具有更大的优势。同时,这些消息优势存在于内核中,由“队列ID”来标识。

2. 消息队列编程

2.1 编程说明

消息队列的实现包括以下4种操作:

  • 创建或打开消息队列,使用 msgget() 函数
  • 添加消息,使用 msgsnd() 函数
  • 读取消息,使用 msgrcv() 函数
  • 控制消息队列,使用 msgctl() 函数
2.2 函数介绍

msgget() 函数

/*****msgget()函数*****/
函数原型:int msgget(key_t key, int msgflg)
传 入 值:key 消息队列的键值,多个进程可通过它访问同一个消息队列。IPC_PRIVATE用于创建私有消息队列
		 msgflg 权限标志位
返 回 值:成功:消息队列ID;
		 失败:返回-1

msgsnd() 函数

/*****msgsnd()函数*****/
函数原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
传 入 值:msqid 消息队列的队列ID
		 msgp 指向消息结构的指针
		 msgsz 消息正文的字节数
		 msgflg 若为0表示调用阻塞直到发送成功为止;IPC_NOWAIT表示若消息无法立即发送,函数会立即返回
返 回 值:成功:返回0;失败:返回-1

//消息结构msgbuf的定义
struct msgbuf{
    
    
	long mtype;		//消息类型,该结构必须从这个域开始
	char mtext[1];	//消息正文
}

msgrcv() 函数

/*****msgrcv()函数*****/
函数原型:int msgrcv(int msgid, void *msgp, size_t msgsz, long int msgtyp, int msgflg)
传 入 值:msqid 消息队列的队列ID
		 msgp 指向消息结构的指针,msgsnd()函数的msgp
		 msgsz 消息正文的字节数
		 msgtyp -->0表示接收消息队列中第一消息;
		 		-->大于0表示接收消息队列中第一个类型为msgtyp的消息;
		 		-->小于0表示接收消息队列中第一个类型值不小于msgtyp绝对值且类型值最小的消息
		 msgflg -->MSG_NOERROR 若返回的消息比msgsz字节多,则消息就会截短到msgsz字节,且不通知消息发送进程;
		 		-->IPC_NOWAIT 若在消息队列中没有相应类型的消息可以接收,则函数立即返回;
		 		-->0 msgsnd()调用阻塞直到接收一条相应类型的消息位置;
返 回 值:成功:返回0
		 失败:返回-1

msgctl() 函数

/*****msgctl()函数*****/
函数原型:int msgctl(int msgid, int cmd, struct msqid_ds *buf)
传 入 值:msqid 消息队列的队列ID
		 cmd -->IPC_STAT 读取消息队列的数据结构msqid_ds,并将其存储在buf指定的地址中;
		     -->IPC_SET 设置消息队列的数据结构msgid_ds中的ipc_perm域值,这个值取自buf参数;
		 	 -->IPC_RMID 从系统内核中删除消息队列;
		 buf 描述消息队列的msqid_ds结构类型变量
返 回 值:成功:返回0
		 失败:返回-1
2.3 函数实例

下面的实例体现了如何使用消息队列进行两个进程(发送端和接收端)之间的通讯。消息发送端进程和消息接收端进程间不需要额外实现进程间的同步。
消息对发送端代码如下:

/*****msgsnd.c*****/
//省略头文件
#define BUFFER_SIZE 512

struct message{
    
    
	long msg_type;
	char msg_text[BUFFER_SIZE];
};

int main(){
    
    
	int qid;
	key_t key;
	strcut message msg;

	if((key = ftok(".",'a')) == -1){
    
    
		perror("ftok");
		exit(1);
	}
	
	if((qid = msgget(key, IPC_CREAT|0666)) == -1){
    
    
		perror("msgget");
		exit(1);
	}
	printf("Open queue %d\n",qid);
	while(1){
    
    
		printf("Enter some message to the queue:");
		if((fgets(msg.msg_text,BUFFER_SIZE,stdin)) == NULL){
    
    
			puts("no message");
			exit(1);
		}

		msg.msg_type = getpid();
		if((msgsnd(qid, &msg, strlen(msg.msg_text), 0)) < 0){
    
    
			perror("message posted");
			exit(1);
		}
		if((strncmp(msg.msg_text, "quit", 4)) == 0)
			break;
	}
	exit(0);
}

消息队列接收端的代码如下:

/*****msgrcv.c*****/
//省略头文件
#define BUFFER_SIZE 512

struct message{
    
    
	long msg_type;
	char msg_text[BUFFER_SIZE];
};

int main(){
    
    
	int qid;
	key_t key;
	strcut message msg;

	if((key = ftok(".",'a')) == -1){
    
    
		perror("ftok");
		exit(1);
	}
	
	if((qid = msgget(key, IPC_CREAT|0666)) == -1){
    
    
		perror("msgget");
		exit(1);
	}
	printf("Open queue %d\n",qid);
	do{
    
    
		memset(msg.msg_text, 0, BUFFER_SIZE);
		if((msgrcv(qid, (void *)&msg, BUFFER_SIZE, 0, 0)) < 0){
    
    
			perror("msgrcv");
			exit(1);
		}
		printf("The message from process %d : %s",msg.msg_type,msg_msg_text);		
	}while(strncmp(msg.msg_text, "quit", 4));
	
	if((msgctl(qid, IPC_RMID, NULL)) < 0){
    
    
		perror("msgctl");
		exit(1);
	}	
	exit(0);
}

猜你喜欢

转载自blog.csdn.net/Chuangke_Andy/article/details/108306421