1. 程式人生 > >Linux程序間通訊——使用訊息佇列

Linux程序間通訊——使用訊息佇列

下面來說說如何用不用訊息佇列來進行程序間的通訊,訊息佇列與命名管道有很多相似之處。有關命名管道的更多內容可以參閱我的另一篇文章:Linux程序間通訊——使用命名管道 一、什麼是訊息佇列 訊息佇列提供了一種從一個程序向另一個程序傳送一個數據塊的方法。  每個資料塊都被認為含有一個型別,接收程序可以獨立地接收含有不同型別的資料結構。我們可以通過傳送訊息來避免命名管道的同步和阻塞問題。但是訊息佇列與命名管道一樣,每個資料塊都有一個最大長度的限制。 Linux用巨集MSGMAX和MSGMNB來限制一條訊息的最大長度和一個佇列的最大長度。 二、在Linux中使用訊息佇列 Linux提供了一系列訊息佇列的函式介面來讓我們方便地使用它來實現程序間的通訊。它的用法與其他兩個System V PIC機制,即訊號量和共享記憶體相似。 1、msgget函式
該函式用來建立和訪問一個訊息佇列。它的原型為:
int msgget(key_t, key, int msgflg);
與其他的IPC機制一樣,程式必須提供一個鍵來命名某個特定的訊息佇列。msgflg是一個許可權標誌,表示訊息佇列的訪問許可權,它與檔案的訪問許可權一樣。msgflg可以與IPC_CREAT做或操作,表示當key所命名的訊息佇列不存在時建立一個訊息佇列,如果key所命名的訊息佇列存在時,IPC_CREAT標誌會被忽略,而只返回一個識別符號。 它返回一個以key命名的訊息佇列的識別符號(非零整數),失敗時返回-1. 2、msgsnd函式 該函式用來把訊息新增到訊息佇列中。它的原型為:
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
msgid是由msgget函式返回的訊息佇列識別符號。 msg_ptr是一個指向準備傳送訊息的指標,但是訊息的資料結構卻有一定的要求,指標msg_ptr所指向的訊息結構一定要是以一個長整型成員變數開始的結構體,接收函式將用這個成員來確定訊息的型別。所以訊息結構要定義成這樣:
struct my_message{
    long int message_type;
    /* The data you wish to transfer*/
};
msg_sz是msg_ptr指向的訊息的長度,注意是訊息的長度,而不是整個結構體的長度,也就是說msg_sz是不包括長整型訊息型別成員變數的長度。
msgflg用於控制當前訊息佇列滿或佇列訊息到達系統範圍的限制時將要發生的事情。 如果呼叫成功,訊息資料的一分副本將被放到訊息佇列中,並返回0,失敗時返回-1. 3、msgrcv函式 該函式用來從一個訊息佇列獲取訊息,它的原型為
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
msgid, msg_ptr, msg_st的作用也函式msgsnd函式的一樣。 msgtype可以實現一種簡單的接收優先順序。如果msgtype為0,就獲取佇列中的第一個訊息。如果它的值大於零,將獲取具有相同訊息型別的第一個資訊。如果它小於零,就獲取型別等於或小於msgtype的絕對值的第一個訊息。 msgflg用於控制當佇列中沒有相應型別的訊息可以接收時將發生的事情。 呼叫成功時,該函式返回放到接收快取區中的位元組數,訊息被複制到由msg_ptr指向的使用者分配的快取區中,然後刪除訊息佇列中的對應訊息。失敗時返回-1. 4、msgctl函式 該函式用來控制訊息佇列,它與共享記憶體的shmctl函式相似,它的原型為:
int msgctl(int msgid, int command, struct msgid_ds *buf);
command是將要採取的動作,它可以取3個值,     IPC_STAT:把msgid_ds結構中的資料設定為訊息佇列的當前關聯值,即用訊息佇列的當前關聯值覆蓋msgid_ds的值。     IPC_SET:如果程序有足夠的許可權,就把訊息列隊的當前關聯值設定為msgid_ds結構中給出的值
    IPC_RMID:刪除訊息佇列 buf是指向msgid_ds結構的指標,它指向訊息佇列模式和訪問許可權的結構。msgid_ds結構至少包括以下成員:
struct msgid_ds
{
    uid_t shm_perm.uid;
    uid_t shm_perm.gid;
    mode_t shm_perm.mode;
};
成功時返回0,失敗時返回-1. 三、使用訊息佇列進行程序間通訊 馬不停蹄,介紹完訊息佇列的定義和可使用的介面之後,我們來看看它是怎麼讓程序進行通訊的。由於可以讓不相關的程序進行行通訊,所以我們在這裡將會編寫兩個程式,msgreceive和msgsned來表示接收和傳送資訊。根據正常的情況,我們允許兩個程式都可以建立訊息,但只有接收者在接收完最後一個訊息之後,它才把它刪除。 接收資訊的程式原始檔為msgreceive.c的原始碼為:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>

struct msg_st
{
	long int msg_type;
	char text[BUFSIZ];
};

int main()
{
	int running = 1;
	int msgid = -1;
	struct msg_st data;
	long int msgtype = 0; //注意1

	//建立訊息佇列
	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*)&data, BUFSIZ, msgtype, 0) == -1)
		{
			fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
			exit(EXIT_FAILURE);
		}
		printf("You wrote: %s\n",data.text);
		//遇到end結束
		if(strncmp(data.text, "end", 3) == 0)
			running = 0;
	}
	//刪除訊息佇列
	if(msgctl(msgid, IPC_RMID, 0) == -1)
	{
		fprintf(stderr, "msgctl(IPC_RMID) failed\n");
		exit(EXIT_FAILURE);
	}
	exit(EXIT_SUCCESS);
}
傳送資訊的程式的原始檔msgsend.c的原始碼為:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#include <errno.h>

#define MAX_TEXT 512
struct msg_st
{
	long int msg_type;
	char text[MAX_TEXT];
};

int main()
{
	int running = 1;
	struct msg_st data;
	char buffer[BUFSIZ];
	int msgid = -1;

	//建立訊息佇列
	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)
	{
		//輸入資料
		printf("Enter some text: ");
		fgets(buffer, BUFSIZ, stdin);
		data.msg_type = 1;    //注意2
		strcpy(data.text, buffer);
		//向佇列傳送資料
		if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1)
		{
			fprintf(stderr, "msgsnd failed\n");
			exit(EXIT_FAILURE);
		}
		//輸入end結束輸入
		if(strncmp(buffer, "end", 3) == 0)
			running = 0;
		sleep(1);
	}
	exit(EXIT_SUCCESS);
}
執行結果如下:
四、例子分析——訊息型別 這裡主要說明一下訊息型別是怎麼一回事,注意msgreceive.c檔案main函式中定義的變數msgtype(註釋為注意1),它作為msgrcv函式的接收資訊型別引數的值,其值為0,表示獲取佇列中第一個可用的訊息。再來看看msgsend.c檔案中while迴圈中的語句data.msg_type = 1(註釋為注意2),它用來設定傳送的資訊的資訊型別,即其傳送的資訊的型別為1。所以程式msgreceive能夠接收到程式msgsend傳送的資訊。 如果把注意1,即msgreceive.c檔案main函式中的語句由long int msgtype = 0;改變為long int msgtype = 2;會發生什麼情況,msgreceive將不能接收到程式msgsend傳送的資訊。因為在呼叫msgrcv函式時,如果msgtype(第四個引數)大於零,則將只獲取具有相同訊息型別的第一個訊息,修改後獲取的訊息型別為2,而msgsend傳送的訊息型別為1,所以不能被msgreceive程式接收。重新編譯msgreceive.c檔案並再次執行,其結果如下:
我們可以看到,msgreceive並沒有接收到資訊和輸出,而且當msgsend輸入end結束後,msgreceive也沒有結束,通過jobs命令我們可以看到它還在後臺執行著。 五、訊息佇列與命名管道的比較 訊息佇列跟命名管道有不少的相同之處,通過與命名管道一樣,訊息佇列進行通訊的程序可以是不相關的程序,同時它們都是通過傳送和接收的方式來傳遞資料的。在命名管道中,傳送資料用write,接收資料用read,則在訊息佇列中,傳送資料用msgsnd,接收資料用msgrcv。而且它們對每個資料都有一個最大長度的限制。 與命名管道相比,訊息佇列的優勢在於,1、訊息佇列也可以獨立於傳送和接收程序而存在,從而消除了在同步命名管道的開啟和關閉時可能產生的困難。2、同時通過傳送訊息還可以避免命名管道的同步和阻塞問題,不需要由程序自己來提供同步方法。3、接收程式可以通過訊息型別有選擇地接收資料,而不是像命名管道中那樣,只能預設地接收。

相關推薦

Linux程序通訊——訊息佇列應用例項

    訊息佇列是訊息的連結表,包括Posix訊息佇列system V訊息佇列。有足夠許可權的程序可以向佇列中新增訊息,被賦予讀許可權的程序則可以讀走佇列中的訊息。訊息佇列克服了訊號承載資訊量少,管道只能承載無格式位元組流以及緩衝區大小受限等缺點。下面是兩個測試模組接收模組m

linux程序通訊--訊息佇列相關函式(ftok)詳解

ipc_perm中mode的含義 操作者 讀 寫 可讀可寫 使用者 0400 0200 0600 組 0040 0020 0060 其他 0004 0002 0006 5.  IPC物件的建立許可權     msgget、semget、sh

Linux 程序通訊——訊息佇列實現雙向通訊

函式: key_t ftok(const char *filename, int proj_id); 通過檔名和專案號獲得System V IPC鍵值(用於建立訊息佇列、共享記憶體所用) proj_id:專案號,不為0即可 返回:成功則返回鍵值,失敗則返回-1 函式: in

Linux關於程序通訊訊息佇列

訊息佇列概念 訊息佇列提供了一個從一個程序向另外一個程序傳送一塊資料的方法 每個資料塊都被認為是有一個型別,接收者程序接收的資料塊可以有不同的型別值 訊息佇列也有管道一樣的不足,就是每個資料塊的最大長度是有上限的,系統上全體佇列的最大總長度也有一個上限 訊息佇列函式操作

一步一步學linux程序通訊——訊息佇列

一、什麼是訊息佇列:訊息佇列提供了一種程序與程序間傳送資料塊的一種方法,每個資料塊含有一個型別,接收程序可以獨立地接收含有不同型別的資料結構,可以通過傳送訊息來避免同步和阻塞問題。訊息佇列有最大長度限制       在分散式計算環境下,訊息佇列是為了對異構網路環境下的分散式應

php程序通訊--訊息佇列

首先我們來看一下如何建立一個訊息佇列。 //建立訊息佇列 $msg_key = ftok( __FILE__, 'a' ); $msg_queue = msg_get_queue( $msg_key, 0666 );  在php中通過這兩句話就可以建立一個訊息佇列。 ftok 函式,是可以

python 多程序通訊 訊息佇列

import multiprocessing import time #使用佇列,將訊息寫進佇列,需要的程序到佇列取 #佇列由父程序建立,子程序共享佇列 def write(qe): print("啟動子程序 write") for chr in ['A','B','C','D

程序通訊——訊息佇列

每個程序各自具有不同的使用者地址空間,任何一個程序的全域性變數在另外一個程序中看不到;所以程序之間要交換資料必須通過核心,在核心中開闢一塊緩衝區,程序1把資料從使用者空間拷到核心緩衝區,程序2再從核心緩

System V程序通訊---訊息佇列

一、訊息佇列模型 訊息佇列是訊息的鏈式佇列,下圖即為訊息佇列模型… 1、訊息佇列的基本屬性 struct msqid_ds { struct msqid_ds { struct ipc_perm msg_perm;

PHP 程序通訊——訊息佇列(msg_queue)

PHP 程序間通訊——訊息佇列 本文不涉及PHP基礎庫安裝。詳細安裝說明,請參考官網,或期待後續部落格分享。 1、訊息佇列函式準備 <?php //生成一個訊息佇列的key $msg_key = ftok(__FILE__, 'a'); //產生一個訊息佇列

LinuxLinux程序通訊訊息佇列

1、訊息佇列概念引入    訊息佇列提供了一個從一個程序向另外一個程序傳送一塊資料的方法每個資料塊都被認為是有一個型別,接收者程序接收的資料塊可以有不同的型別值訊息佇列也有管道一樣的不足,就是每個訊息的最大長度是有上限的(MSG

Linux程序通訊(IPC)程式設計實踐(十二)Posix訊息佇列--基本API的使用

posix訊息佇列與system v訊息佇列的差別: (1)對posix訊息佇列的讀總是返回最高優先順序的最早訊息,對system v訊息佇列的讀則可以返回任意指定優先順序的訊息。 (2)當往一個空佇列放置一個訊息時,posix訊息佇列允許產生一個訊號或啟動一個執行緒,

Linux程序通訊--訊號,管道,訊息佇列,訊號量,共享記憶體,socket

Linux 傳統的程序間通訊有很多,如各類管道、訊息佇列、記憶體共享、訊號量等等。但它們都無法介於核心態與使用者態使用,原因如表 通訊方法 無法介於核心態與使用者態的原因 管道(不包括命名管道) 侷限於父子程序間的通訊。 訊息佇列 在硬、軟中斷中無法無阻塞地接收資料。 訊號量 無法介於核

Linux程序通訊之POSIX訊息佇列

訊息佇列可認為是一個訊息連結串列,它允許程序之間以訊息的形式交換資料。有足夠寫許可權的程序或執行緒可往佇列中放置訊息,有足夠讀許可權的程序或執行緒可從佇列中取走訊息。每個訊息都是一個記錄,它由傳送者賦予一個優先順序。與管道不同,管道是位元組流模型,沒有訊息邊界。

Linux程序通訊之訊號量(semaphore)、訊息佇列(Message Queue)和共享記憶體(Share Memory)

System V 程序通訊方式:訊號量(semaphore)、訊息佇列(Message Queue)和共享記憶體(Share Memory) 訊號量 訊號量(semaphore)實際是一個整數,它的值由多個程序進行測試(test)和設定(set)。就每個程序所關心的測試和

Linux程序通訊——使用訊息佇列

下面來說說如何用不用訊息佇列來進行程序間的通訊,訊息佇列與命名管道有很多相似之處。有關命名管道的更多內容可以參閱我的另一篇文章:Linux程序間通訊——使用命名管道 一、什麼是訊息佇列 訊息佇列提供了一種從一個程序向另一個程序傳送一個數據塊的方法。  每個資料塊都被認為含

linux 程序通訊訊息佇列以及例項

程式碼來自:嵌入式linux應用開發標準教程 訊息可以理解為寫信給某個人,這裡在應用中是告訴系統寫信人和寫信的內容就可以了, 別人會來看發信人是誰,如果不是自己想要的就放棄讀信或者只要有訊息自己就讀取訊息 訊息佇列就是按佇列的方式處理很多訊息,先發的最先被讀 訊息佇列:

Linux---程序通訊IPC之訊息佇列

**程序間通訊(IPC):**是指在不同程序之間傳播或交換資訊。 **IPC的方式:**通常有管道(無名管道、命名管道)、訊息佇列、訊號量、共享儲存、Socket、Streams等(Socket和Streams支援不同主機上的兩個程序IPC) 程序間通訊的目

Linux程序通訊(IPC)程式設計實踐(三) 詳解System V訊息佇列(1)

訊息佇列簡介 訊息佇列提供了一個從一個程序向另外一個程序傳送一塊資料的方法(本機);每個資料塊都被認為是有一個型別,接收者程序接收的資料塊可以有不同的型別值。訊息佇列也有管道一樣的不足:  (1)每

Linux-程序通訊訊息對列)

今天來介紹IPC通訊的第一種方式:訊息對列 由於程序具有獨立性,要想兩個程序之間有資料的往來,就必須讓兩個不相干的程序看到同一塊資源。前面有講到管道,也是一種公共資源。現在,我們介紹一種另一種公共資源:訊息對列 訊息對列,顧名思義,想必看到的公共資源可能就是