1. 程式人生 > >Linux的程序程式設計-之二-程序間通訊(訊息佇列)

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。