進程間通信(IPC):消息隊列

進程間通信(IPC):消息隊列

消息隊列,是消息的鏈接表,存放在內核中。一個消息隊列由一個標識符(即隊列ID)來標識。

特點

(1)消息隊列是消息的鏈表,具有特定的格式,存放在內存中並由消息隊列標識符標識.
(2)消息隊列允許一個或多個進程向它寫入與讀取消息.
(3)管道和消息隊列的通信數據都是先進先出的原則。
(4)消息隊列可以實現消息的隨機查詢,消息不一定要以先進先出的次序讀取,也可以按消息的類型讀取.比FIFO更有優勢。
(5)消息隊列克服了信號承載信息量少,管道只能承載無格式字 節流以及緩衝區大小受限等缺。
(6)目前主要有兩種類型的消息隊列:POSIX消息隊列以及System V消息隊列,系統V消息隊列目前被大量使用。系統V消息隊列是隨內核持續的,只有在內核重起或者人工刪除時,該消息隊列纔會被刪除。

Linux提供了一組消息隊列函數讓我們使用消息隊列,消息隊列函數定義如下:

#include <sys/msg.h>
int msgget(key_t key, int msgflg);
/*
函數msgget用於得到一個已存在的消息隊列標識符或創建一個消息隊列對象。
參數key表示消息隊列的鍵值,用於標識一個消息隊列,函數將它與已有的消息隊列對象的鍵值比較,以此來判斷消息隊列對象是否已經創建。key_t是一個32位整型;參數mflag表示創建或訪問消息隊列的具體方式。
如果函數執行成功返回一個正數作爲消息隊列標識符,失敗返回-1,通過errno可以獲取錯誤碼。
*/

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
/*
函數msgctl用於獲取和設置消息隊列的屬性。
參數msqid是消息隊列標識符;cmd表示要對消息隊列進行的操作;buf指向消息隊列管理結構體msqid_ds。
如果函數執行成功返回0,失敗返回-1,通過errno可以獲取錯誤碼。
*/

int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflag);
/*
函數msgsnd用來將消息送入消息隊列。
參數msqid是消息隊列標識符;msg_ptr表示消息緩衝區指針,用來暫時存儲要發送的消息;msg_sz是要發送信息的長度(字節數);msgflag是控制函數行爲的標誌。
如果函數執行成功返回0,失敗返回-1,通過errno可以獲取錯誤碼。
*/

int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflag);
/*
函數msgrcv用於從消息隊列中讀出一條新消息。
參數msqid是消息隊列標識符;msg_ptr指向要讀出消息的緩衝區;msg_sz是消息數據的長度(字節數);msgtype表示從消息隊列內讀取的消息形態,0代表消息隊列中的所有消息都會被讀取;msgflag是控制函數行爲的標誌。
如果函數執行成功返回讀取的字節數,失敗返回-1,通過errno可以獲取錯誤碼。
*/

消息隊列的發送與接收

接收:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct my_msg_st	//	將要發送的消息
{
	long int my_msg_type;	
	char some_text[BUFSIZ];
};

int main()
{
	int running = 1;
	int msgid;
	struct my_msg_st some_data;
	long int msg_to_receive = 0;	//	讀取消息隊列中的全部消息
	
    //	創建消息隊列
	msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
	if(msgid == -1) 
	{
		fprintf(stderr, "msgget failed with error: %d\n", errno);
		exit(EXIT_FAILURE);
	}
	
    //	接收消息隊列中的消息直到遇到一個end消息。最後,消息隊列被刪除
	while(running)
	{
		if(msgrcv(msgid, (void *)&some_data, BUFSIZ, msg_to_receive, 0) == -1)
		{
			fprintf(stderr, "msgrcv failed with error: %d\n", errno);
			exit(EXIT_FAILURE);
		}
		
		printf("You wrote: %s", some_data.some_text);
		if(strncmp(some_data.some_text, "end", 3) == 0)
		{
			running = 0;
		}
	}
	
    //	刪除消息隊列
	if(msgctl(msgid, IPC_RMID, 0) == -1)
	{
			fprintf(stderr, "msgctl failed with error: %d\n", errno);
			exit(EXIT_FAILURE);
	}
	
	exit(EXIT_SUCCESS);
}

發送:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define MAX_TEXT 512

struct my_msg_st
{
	long int my_msg_type;
	char some_text[MAX_TEXT];
};

int main()
{
	int running = 1;
	int msgid;
	struct my_msg_st some_data;
	char buffer[BUFSIZ];
	
	msgid = msgget((key_t)1234, 0666 | IPC_CREAT);	//	用一個整數作爲鍵值
	if(msgid == -1) 
	{
		fprintf(stderr, "msgget failed with error: %d\n", errno);
		exit(EXIT_FAILURE);
	}
	
	while(running)
	{
		printf("Enter some text:");
		fgets(buffer, BUFSIZ, stdin);
		some_data.my_msg_type = 1;
		strcpy(some_data.some_text, buffer);
			
		if(msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1)
		{
			fprintf(stderr, "msgsnd failed with error: %d\n", errno);
			exit(EXIT_FAILURE);
		}
		
		printf("You wrote: %s", some_data.some_text);
		if(strncmp(some_data.some_text, "end", 3) == 0)
		{
			running = 0;
		}
	}
	
	
	exit(EXIT_SUCCESS);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章