Linux IPC 消息隊列 創建訪問 msgget,發送信息 msgsnd,接受信息 msgrcv,刪除 msgctl

消息隊列

消息隊列與 FIFO 很相似,都是一個隊列結構,都可以有多個進程往隊列裏面寫信息,多個進程從隊列中讀取信息。但 FIFO 需要讀、寫的兩端事先都打開,才能夠開始信息傳遞工作。而消息隊列可以事先往隊列中寫信息,需要時再打開讀取信息。但是,消息隊列先打開讀,仍然會阻塞,因爲此時沒有消息可讀。
函數原型:

#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/msg.h> 
int msgget(key_t key, int msgflg); 
int msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg); 
ssize_t  msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg); 
int msgctl(int msqid, int cmd, struct msqid_ds *buf); 

函數 msgget()

int msgget(key_t key, int msgflg);

創建和訪問一個消息隊列。該函數成功則返回一個唯一的消息隊列標識符(類似於進程 ID 一樣),失敗則返回-1。

參數 key 是唯一標識一個消息隊列的關鍵字,如果爲IPC_PRIVATE(值爲 0),用創建一個只有創建者進程纔可以訪問的消息隊列, 可以用於父子間通信; 非0值的 key值(可以通過 ftok 函數獲得)表示創建一個可以被多個進程共享的消息隊列;

參數 msgflg 指明消息隊列的訪問權限和創建標誌,創建標誌的可選值爲IPC_CREATIPC_EXCL 。如果單獨指定 IPC_CREAT,msgget 要麼返回新創建的消息隊列 id,要麼返回具有相同 key 值的消息隊列 id。 如果 IPC_EXCL 和 IPC_CREAT 同時設定, 則要麼創建新的消息隊列,要麼當隊列存在時,調用失敗並返回-1。

msgget.c

#include <func.h>

typedef struct msgbuf{
    long mtype;
    char mtext[64];
}MSG_T;

int main(int argc, char* argv[])
{
    int msgid=msgget(1000,IPC_CREAT|0600);
    ERROR_CHECK(msgid,-1,"msgget");
    struct msgbuf msgInfo;
    msgInfo.mtype = 1;
    strcpy(msgInfo.mtext,"hello");
    int ret=msgsnd(msgid,&msgInfo,strlen(msgInfo.mtext),0);
    ERROR_CHECK(ret,-1,"msgsnd");
    return 0;
}

函數msgsnd()和函數msgrcv()

int msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg); 
ssize_t  msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg); 

函數 msgsnd 和 msgrcv 用來將消息添加到消息隊列中和從一個消息隊列中獲取信息。

參數 msgid 指明消息隊列的 ID; 通常是 msgget 函數成功的返回值。

參數 msgbuf 是消息結構體,它的長度必須小於系統規定的上限,必須以一個長整型成員變量開始, 接收函數將用這個成員變量來確定消息的類型。 必須重寫這個結構體,其中第一個參數不能改,其他自定義。如下:

struct msgbuf { 
	long mtype;         /* type of message */ 
	char mtext[1];       /* message text */ 
}; 

字段 mtype 是用戶自己指定的消息類型(必須是正整數),該結構體第 2 個成員僅僅是一種說明性的結構,實際上用戶可以使用任何類型的數據,指消息內容。

參數 msgsz 是消息體的大小,每個消息體最大不要超過 4K。

參數 msgflg 可以爲 0(通常爲 0)或 IPC_NOWAIT,如果設置 IPC_NOWAIT,則msgsnd 和 msgrcv 都不會阻塞,此時如果隊列滿並調用 msgsnd 或隊列空時調用 msgrcv將返回錯誤。

參數 msgtyp 有 3 種選項:

msgtyp == 0      接收隊列中的第 1 個消息(通常爲 0) 
msgtyp > 0      接收對列中的第 1 個類型等於 msgtyp 的消息 
msgtyp < 0      接收其類型小於或等於 msgtyp 絕對值的第 1 個最低類型消息 

msgget_msgsnd.c

#include <func.h>

typedef struct msgbuf{
    long mtype;
    char mtext[64];
}MSG_T;

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc,3);
    int msgid=msgget(1000,IPC_CREAT|0600);
    ERROR_CHECK(msgid,-1,"msgget");
    struct msgbuf msgInfo;
    msgInfo.mtype = atoi(argv[1]);
    strcpy(msgInfo.mtext,argv[2]);
    int ret=msgsnd(msgid,&msgInfo,strlen(msgInfo.mtext),0);
    ERROR_CHECK(ret,-1,"msgsnd");
    return 0;
}

msgget_msgrcv.c

#include <func.h>

typedef struct msgbuf{
    long mtype;
    char mtext[64];
}MSG_T;

int main(int argc, char* argv[])
{
    int msgid=msgget(1000,IPC_CREAT|0600);
    ERROR_CHECK(msgid,-1,"msgget");
    struct msgbuf msgInfo;
    msgInfo.mtype = 1;
    strcpy(msgInfo.mtext,"hello");
    int ret=msgsnd(msgid,&msgInfo,strlen(msgInfo.mtext),0);
    ERROR_CHECK(ret,-1,"msgsnd");
    return 0;
}

msgget_msgrcv_nowait.c

#include <func.h>

typedef struct msgbuf{
    long mtype;
    char mtext[64];
}MSG_T;

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc,2);
    int msgid=msgget(1000,IPC_CREAT|0600);
    ERROR_CHECK(msgid,-1,"msgget");
    struct msgbuf msgInfo;
    bzero(&msgInfo,sizeof(msgInfo));
    int ret=msgrcv(msgid,&msgInfo,sizeof(msgInfo.mtext),atoi(argv[1]),IPC_NOWAIT);
    printf("errno=%d\n",errno);
    ERROR_CHECK(ret,-1,"msgrcv");
    printf("mtype=%ld,mtext=%s\n",msgInfo.mtype,msgInfo.mtext);
    return 0;
}

函數msgctl()

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

函數 msgctl 是消息隊列的控制函數,常用來刪除消息隊列

msgctl() performs the control operation specified by cmd on the System V message queue with identifier msqid.

參數 msqid 是由 msgget 返回的消息隊列標識符。
參數 cmd 通常爲 IPC_RMID 表示刪除消息隊列。

IPC_STAT: 讀取消息隊列的數據結構msqid_ds,並將其存儲在buf指定的地址

IPC_STAT: Copy information from the kernel data structure associated with msqid into the msqid_ds structure pointed to by buf. The caller must have read permission on the message queue.

IPC_SET: 設置消息隊列的數據結構msqid_ds中的ipc_perm元素的值。這個值取自buf參數

IPC_SET: Write the values of some members of the msqid_ds structure pointed to by buf to the kernel data structure associated with this message queue, updating also its msg_ctime member. The following members of the structure are updated: msg_qbytes, msg_perm.uid, msg_perm.gid, and msg_perm.mode.

IPC_RMID: 從系統內核中移走消息隊列

IPC_RMID: Immediately remove the message queue, awakening all waiting reader and writer pro‐cesses (with an error return and errno set to EIDRM).

參數 buf 通常爲 NULL 即可。

消息隊列的msqid_ds結構,描述了消息隊列當前的狀態。對於每一個消息隊列都有一個msqid_ds來描述消息隊列當前的狀態。

struct msqid_ds:

struct msqid_ds {
	struct ipc_perm msg_perm;     /* Ownership and permissions */
	time_t          msg_stime;    /* Time of last msgsnd(2) */
	time_t          msg_rtime;    /* Time of last msgrcv(2) */
	time_t          msg_ctime;    /* Time of last change */
	unsigned long   __msg_cbytes; /* Current number of bytes in queue (nonstandard)*/
	msgqnum_t       msg_qnum;     /* Current number of messages in queue */
	msglen_t        msg_qbytes;   /* Maximum number of bytes allowed in queue */
	pid_t           msg_lspid;    /* PID of last msgsnd(2) */
	pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
};

struct ipc_perm:

消息隊列中的數據結構中唯一可以改動的元素就是ipc_perm。它包括隊列的存取權限和關於隊列創建者和擁有者的信息。僅可以改變用戶的id、用戶的組id以及消息隊列的存取權限

The ipc_perm structure is defined as follows , the highlighted fields are settable using IPC_SET
uid gid mode

struct ipc_perm {
	key_t          __key;       /* Key supplied to msgget(2) */
	uid_t          uid;         /* Effective UID of owner */
	gid_t          gid;         /* Effective GID of owner */
	uid_t          cuid;        /* Effective UID of creator */
	gid_t          cgid;        /* Effective GID of creator */
	unsigned short mode;        /* Permissions */
	unsigned short __seq;       /* Sequence number */
};

msgget_msgctl.c

#include <func.h>

typedef struct msgbuf{
    long mtype;
    char mtext[64];
}MSG_T;

int main(int argc, char* argv[])
{
    int msgid=msgget(1000,IPC_CREAT|0600);
    ERROR_CHECK(msgid,-1,"msgget");
    int ret=msgctl(msgid,IPC_RMID,NULL);
    ERROR_CHECK(ret,-1,"msgctl");
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章