近正好有一些空餘時間,在這裡總結一下曾經使用過的linux程序間通訊的幾種方法,貼出來幫助有需要的人,也有助於自己總結經驗加深理解。上一次我們梳理了
共享記憶體
的相關知識,這一次梳理訊息佇列。
(一)概念
在介紹訊息佇列之前,我們先來簡單說一說system v ipc通訊機制。
system v ipc機制最初是由at&t system v.2版本的unix引入的。這些機制是專門用於ipc(inter-process communication 程序間通訊)的,它們在同乙個版本中被應用,又有著相似的程式設計介面,所以它們通常被稱為system v ipc通訊機制。
訊息佇列是最後乙個system v ipc機制。訊息佇列的本質也是在不同的執行緒之間共享的一段記憶體。只是它與共享記憶體不同,程式不能夠直接通過api讀取或者寫入這段共享記憶體。而它有著自己的特殊機制,就像一段佇列,傳送者可以向訊息佇列中加入一段訊息,而負責接收的程式責可以從佇列中讀取一則訊息。先被傳送的訊息將先被讀取,也不用程式開發者去考慮同步相關的事情。系統會幫你確保它。
(二)訊息佇列的建立,傳送,接收和銷毀
同樣於共享記憶體,system v提供了一套極其類似的api供開發者們操作訊息佇列。雖然api非常類似,但是它內部的機制則差異很大,這使得訊息佇列和共享記憶體的應用場景也有很大不同。我們先來介紹一下操作訊息佇列的主要api。
我們可以使用msgget()函式來建立,或者是得到乙個訊息佇列:
int msgget( key_t key, int msg*** );
其中,
--key:是訊息的列的名字,也是系統內訊息佇列的唯一標識。訪問同乙個訊息佇列的不同程序需要使用同乙個名字。
--msg***:訊息佇列的標誌,包含9個位元標誌位,其內容與建立檔案時的mode相同。有乙個特殊的標誌ipc_creat可以和許可權標誌以或的形式傳入。
成功是返回乙個整數標識訊息佇列的控制代碼,失敗是返回-1。
我們可以使用msgsnd()函式來向乙個訊息佇列傳送資訊:
int msgsnd( int msgid, const void* msg_ptr, size_t msg_sz, int msgflt );
其中,
--msgid:是執行緒內訊息佇列的標識,是msgget()的返回值。
--msg_ptr:是訊息結構的指標,它可以是使用者自定義的結構體,不過它必須以長整數開頭(即結構提的第乙個變數必須是長整數),這個長整數表示訊息的型別,這個長整數很重要,因為訊息接收函式會根據它對訊息進行篩選。
--msg_zs:是訊息體的長度,注意它是不包括訊息型別這個長整數的,是除其意外的大小。
--msgflt:控制訊息佇列的標誌,如果在標誌中設定了ipc_nowait,在出現諸如訊息佇列滿了等情況時,函式會立刻返回-1,如果不設定的話函式會掛起一段時間。
我們使用msgrcv()函式來從訊息佇列中讀取乙個訊息:
int msgrcv( int msgid, void* msg_ptr, size_t msg_sz, long int msgtype, int msg*** );
其中,
--msgid:是執行緒內訊息佇列的標識,是msgget()的返回值。
--msg_ptr:是訊息結構的指標,它與msgsnd中的是一樣的。
--msg_zs:是訊息體的長度,注意它是不包括訊息型別這個長整數的,是除其意外的大小。
--msgtype:訊息型別,就是訊息開頭的那一段長整數,設定為0則會從訊息佇列中讀取第一條訊息,設定為》0的值會讀取該型別的第一條訊息。如果設定為<0的值,將會讀取小於該值絕對值的所有型別的第一條訊息。
--msgflt:控制訊息佇列的標誌,如果在標誌中設定了ipc_nowait,在出現諸如訊息佇列滿了等情況時,函式會立刻返回-1,如果不設定的話函式會掛起一段時間。
我們使用msgctg()函式來控制訊息佇列,這一點與共享記憶體非常相似:
int msgctl( int msgid, int command, struct msqid_ds* buf );
其中,
--msg_id:是訊息佇列的標示符,也即是msgget()的返回值。
--command:是要採取的動作,它有三個有效值,如下所示:值說明
ipc_stat
把buf結構中的值設定為共享記憶體的關聯值
ipc_set
如果擁有足夠的許可權,將共享記憶體的值設定為buf中的值
ipc_rmid
刪除共享記憶體段
--buf:是乙個msgid_ds結構的指標它可以設定訊息佇列的關聯值。msgid_ds的結構如下所示
:
struct msgid_ds
(三)使用訊息佇列通訊的例子現在我們就來嘗試寫兩個簡單例子來使用以下訊息佇列,我們首先要寫乙個標頭檔案,定義我們的訊息格式。因為這是個非常簡單的例子,所以我們的訊息結構裡只用乙個長整型的訊息型別(必須),兩外再加上一段字串,它表示具體訊息內容。我們把它儲存為msgdef.h:
#ifndef _msgdef_h_
#define _msgdef_h_
#define msg_fd 1111 /* message id*/
#define msg_text_size 24 /* message text max size definition */
/* structure of general message */
typedef struct message_body
msg_body;
#endif /* _msgdef_h_ */
現在我們來完成訊息接收者,它將從訊息佇列讀取乙個訊息並且列印到螢幕上,建立乙個新檔案msgrecv.c:
#include #include #include #include #include "msgdef.h"
int main()
dowhile( memcmp( message.msg_text, "close", 5 ) != 0 );
/* close the message list. */
msgctl( msgfd, ipc_rmid, 0 );
return 0;
}
然後我們來完成訊息的傳送者,它會讀取使用者的輸入併發送到訊息佇列。我們把它命名為msgsend.c:
#include #include #include #include #include "msgdef.h"
int main()
dowhile( memcmp( message.msg_text, "close", 5 ) != 0 );
return 0;
}
現在我們來編譯一下這兩個程式:
root@workspace-server:/home/root/workspace/msgq/system-v# gcc msgrecv.c -o msgrecv
root@workspace-server:/home/root/workspace/msgq/system-v# gcc msgsend.c -o msgsend
嘗試啟動接收者:
root@workspace-server:/home/root/workspace/msgq/system-v# ./msgrecv
現在我們另外啟動乙個終端,嘗試啟動傳送者,並輸入一下東西:
root@workspace-server:/home/root/workspace/msgq/linux# ./msgsend
please input something:abc
please input something:hellow
please input something:****
please input something:ono
please input something:close
root@workspace-server:/home/root/workspace/msgq/linux#
然後我們看一下接收者那邊的情況:
root@workspace-server:/home/root/workspace/msgq/system-v# ./msgrecv
receive: abc
receive: hellow
receive: ****
receive: ono
receive: close
root@workspace-server:/home/root/workspace/msgq/system-v#
可以看到輸入的內容被通過訊息佇列成功的傳遞了。 Linux基礎入門 程序間通訊 訊息佇列
system v提供的ipc機制主要有訊息佇列,訊號量和共享記憶體3種機制。和檔案一樣,ipc在使用前必須先建立,每種ipc都有特定的生產者,所有者和訪問許可權。使用ipcs命令可以檢視當前系統正在使用的ipc工具 root localhost swz ipcs shared memory segm...
Linux程序間通訊 訊息佇列
linux和類linux系統下程序間通訊 inter process communication,ipc 有很多種方式,包括套接字 socket 共享記憶體 shared memory 管道 pipe 訊息佇列 message queue 等,各自有各自的一些應用場景和用途,這次就來聊一聊訊息佇列這...
linux程序間通訊 訊息佇列
訊息佇列由id 唯一標識 訊息佇列就是乙個訊息的列表,使用者可在佇列中新增,讀取訊息等 可按照型別來收發訊息 int msgget key t key,int flag int msgsnd int msqid,const void msgp,size t size,int flag msqid 訊...