Linux的程序程式設計-之二-程序間通訊(訊息佇列)
1.1 系統V訊息佇列
訊息佇列中的每個訊息都有如下的資料結構:
struct msgbuf
{
long mtype; // 訊息型別
char mtext[n]; // 訊息內容,n由使用者自己定義
};
1.1.1 ftok( )
#include<sys/types.h>
#include<sys/ipc.h>
key_tftok( const char *name, int id )
引數name指定了檔名(包含路徑),該檔案必須存在,而且當前程序必須能夠訪問該檔案。
引數id只有低8位有效。
只有當name和id取值都相同時,返回的鍵值key才是相同的。
成功返回鍵值,失敗返回-1。
1.1.2 msgget( )
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
intmsgget( key_t key, int msgflg )
建立或獲取訊息佇列;成功返回與key相關聯的訊息佇列id,失敗返回-1。
引數msgflg可以取IPC_CREAT、IPC_EXCL、IPC_NOWAIT。
單獨使用IPC_CREAT,如果不存在與鍵值key相關聯的訊息佇列,就建立一個新的訊息佇列,並返回其id,如果已經存在與鍵值key相關聯的訊息佇列,就返回該訊息佇列的id。
單獨使用IPC_EXCL是沒有意義的,如果IPC_EXCL和IPC_CREAT一起使用,當與鍵值key相關聯的訊息佇列已經存在時,就失敗返回-1。
下面兩種情況會建立一個新的訊息佇列:
1.引數msgflg指定IPC_CREAT,而且沒有訊息佇列與鍵值key相關聯;
2.引數key指定IPC_PRIVATE;
引數msgflg的低9位指定新建立訊息佇列的訪問許可權:
所有者 |
組成員 |
其他成員 |
||||||
讀 |
寫 |
執行 |
讀 |
寫 |
執行 |
讀 |
寫 |
執行 |
1.1.3 msgrcv( )
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
ssize_tmsgrcv( int msqid, void *msgp, size_t msgsz, long int msgtyp, int msgflg );
讀取訊息佇列中的一個訊息,存放到msgp指向的msgbuf結構中。
成功返回實際讀出訊息內容的位元組數,並將訊息從訊息佇列中移除;失敗返回-1,不移除訊息。
msgsz指定讀取訊息的長度,即msgbuf結構中mtext[n]的長度。
msgtyp指定讀取訊息的型別:
msgtyp = 0 讀取訊息佇列中的第一個訊息
msgtyp>0 讀取訊息佇列中第一個msgtyp型別的訊息,如果沒有,失敗返回
msgtyp<0 如果訊息佇列中的最小型別≤abs(msgtyp),讀取最小型別的第一個訊息;
如果訊息佇列中的最小型別>abs(msgtyp),失敗返回
引數msgflg可以取值:
IPC_EXCEPT :當msgtyp>0時,返回訊息佇列中第一個型別不是msgtyp的訊息。
IPC_NOWAIT
設定 :如果訊息佇列中沒有滿足條件的訊息,立即失敗返回。
未設定 ;如果訊息佇列中沒有滿足條件的訊息,掛起當前程序,直到以下任一事件發生:
1.滿足條件的訊息出現在訊息佇列中,成功返回;
2.訊息佇列被刪除,失敗返回。
IPC_NOERROR
設定 :如果訊息內容>msgsz,把多餘的訊息內容清除,成功返回。
未設定 :如果訊息長度>msgsz,失敗返回。
1.1.4 msgsnd( )
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
intmsgsnd( int msqid, struct msgbuf *msgp, int msgsz, int msgflg );
向訊息佇列中傳送一個訊息,訊息來源是msgp指向的msgbuf結構。
成功返回0;失敗返回-1。
msgsz指定傳送訊息的長度,即msgbuf結構中mtext[n]的長度。
引數msgflg可以取值:
IPC_NOWAIT
設定 :如果佇列中的訊息內容或訊息數目已經達到上限,立即失敗返回。
未設定 :如果佇列中的訊息內容或訊息數目已經達到上限,掛起當前程序直到任一事件發生:
1.訊息內容或訊息數目恢復正常,成功返回;
2.訊息佇列被刪除,失敗返回。
1.1.5 msgctl( )
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
intmsgctl( int msqid, int cmd, struct msqid_ds *buf );
獲取或設定訊息佇列的屬性,成功返回0;失敗返回-1。
引數cmd可以指定三種操作:
IPC_RMID :刪除指定的訊息佇列。
IPC_STAT :用來獲取訊息佇列的資訊,返回的資訊存放到buf指向的msqid_ds結構中。
IPC_SET :用來設定訊息佇列的屬性,要設定的屬性儲存在buf指向的msqid_ds結構中。
1.2 Posix訊息佇列
1.2.1 訊息佇列的建立和刪除
1.2.1.1 mq_open( )
#include<mqueue.h>
mqd_tmq_open( const char *name, int flag )
mqd_t mq_open( const char *name, int flag, mode_t mode, mq_attrattr )
建立或獲取一個訊息佇列。成功返回訊息佇列描述符;失敗返回-1。
引數name指定與訊息佇列相關聯的名字。
引數flags可以取:
O_RDONLY O_WRONLY O_RDWR(三選一)
O_CREAT
單獨使用O_CREAT,如果不存在與name相關聯的訊息佇列,就建立一個新的訊息佇列,並返回其描述符,如果已經存在與name相關聯的訊息佇列,就返回該訊息佇列的描述符。
如果指定了O_CREAT,需要使用mq_open( )的第二種形式,其中引數mode指定了新建立訊息佇列的訪問許可權,引數attr指定了新建立訊息佇列的屬性。
O_EXCL。
單獨使用O_EXCL是沒有意義的,如果O_EXCL和O_CREAT一起使用,當與name相關聯的訊息佇列已經存在時,就失敗返回。
O_NONBLOCK
決定在mq_send( )和mq_receive( )時是否會掛起當前程序,直到讀取或傳送訊息成功。
1.2.1.2 mq_close( )
#include <mqueue.h>
int mq_close( mqd_t mqdes )
關閉當前程序和指定訊息佇列之間的聯絡。
成功返回0,失敗返回-1。
1.2.1.3 mq_unlink( )
#include <mqueue.h>
int mq_unlink( const char *name )
刪除指定的訊息佇列,但是如果當前仍有其它程序正在使用訊息佇列,則暫時放棄刪除操作,並立即返回,直到其它程序通過呼叫mq_close( )關閉之後,再進行刪除操作。
成功返回0,失敗返回-1。
1.2.2 訊息佇列的屬性
1.2.2.1 mq_getattr( )
#include<mqueue.h>
intmq_getattr( mqd_t mqdes, struct mq_attr *attr )
成功返回0,失敗返回-1。
struct mq_attr
{
long mq_flags; //message queue flags
long mq_maxmsg; //maximum number of messages
long mq_msgsize; // maximummessage size
long mq_curmsgs; // numberof messages currently queued
}
1.2.2.2 mq_setattr( )
#include<mqueue.h>
intmq_setattr( mqd_t mqdes, const struct mq_attr *newAttr, struct mq_attr *oldAttr)
注意:只能設定mq_attr結構中的mq_flags,mq_attr結構中的其它成員將被忽略。
成功返回0,失敗返回-1。
1.2.3 訊息佇列的操作
1.2.3.1 mq_notify()
#include<mqueue.h>
int mq_notify( mqd_t mqdes, const struct sigevent*notification )
成功返回0,失敗返回-1。
為當前程序在指定的訊息佇列上註冊notify操作,當訊息佇列由空變為非空時,也就是說有訊息加入原本為空的訊息佇列時,會觸發程序註冊的nofity操作。
引數notification指定需要註冊的nofity操作。如果引數notification為NULL,而且程序之前註冊過notify操作,會取消之前註冊的notify操作。
需要注意的是:
1.只能有唯一的一個程序在訊息佇列上註冊notify操作。如果已經有其它程序在訊息佇列上註冊了notify操作,試圖再次進行notify()會失敗返回;
2.當程序註冊的nofity操作被觸發之後,該nofity操作就會被刪除,其它程序可以重新向該訊息佇列註冊notify操作。
如果程序已經註冊過notify操作,而且程序在訊息佇列為空時,阻塞呼叫了mq_receive( )(即在mq_open()時設定了O_NONBLOCK),如果有一個訊息到達,會先滿足mq_receive( )呼叫,所以訊息佇列仍然為空,不會觸發notify操作。
struct sigevent
{
int sigev_notify;
int sigev_signo; // signal numbersent to current process when the timer expires
union sigval sigev_value; // info carried with signal
NotifyFUN sigev_notify_function; //typedef void (*NotifyFUN)( union sigval)
pthread_attr_t* sigev_notify_attributes;
}
sigev_notify的取值:
SIGEV_NONE :No notification will be delivered when the event ofinterest occurs.
SIGEV_SIGNAL :A queued signal will be generated when theevent of interest occurs.
SIGEV_THREAD :A notification function will be called toperform notification.
1.2.3.2 mq_receive( )
#include<mqueue.h>
ssize_tmq_receive( mqd_t mqdes, char *msg, size_t len, unsigned int *prio )
讀取the oldest of the highest priority message。
引數len指定讀取訊息的長度,如果len<attr(mq_msgsize),失敗返回。
mq_open( )是否設定O_NONBLOCK,會決定mq_receive( )是否進行阻塞讀取。
成功返回讀取訊息的位元組數,失敗返回-1。
1.2.3.3 mq_send( )
#include<mqueue.h>
intmq_send( mqd_t mqdes, const char *msg, size_t len, unsigned int prio )
引數len指定傳送訊息的長度,如果len>attr(mq_msgsize),失敗返回。
引數prio<MQ_PRIO_MAX。
mq_open( )是否設定O_NONBLOCK,會決定mq_send( )是否進行阻塞傳送。
成功返回0,失敗返回-1。