Linux IPC实践(4) --System V消息队列(1)
消息隊(duì)列概述
? ?消息隊(duì)列提供了一個(gè)從一個(gè)進(jìn)程向另外一個(gè)進(jìn)程發(fā)送一塊數(shù)據(jù)的方法(僅局限于本機(jī));
? ?每個(gè)數(shù)據(jù)塊都被認(rèn)為是有一個(gè)類型,接收者進(jìn)程接收的數(shù)據(jù)塊可以有不同的類型值.
? ?消息隊(duì)列也有管道一樣的不足:?(1)每個(gè)消息的最長字節(jié)數(shù)的上限(MSGMAX);?(2)系統(tǒng)中消息隊(duì)列的總條數(shù)也有一個(gè)上限(MSGMNI);?(3)每個(gè)消息隊(duì)列所能夠保存的總字節(jié)數(shù)是有上限的(MSGMNB)?.
?
查看系統(tǒng)限制
? ?cat?/proc/sys/kernel/msgmax? #最大消息長度限制
? ?cat?/proc/sys/kernel/msgmnb? #消息隊(duì)列總的字節(jié)數(shù)
? ?cat?/proc/sys/kernel/msgmni? #消息條目數(shù)
?
?
管道?vs.?消息隊(duì)列
管道 | 消息 |
流管道 | 有邊界 |
先進(jìn)先出 | 可以后進(jìn)先出 |
IPC對(duì)象數(shù)據(jù)結(jié)構(gòu)
//內(nèi)核為每個(gè)IPC對(duì)象維護(hù)一個(gè)數(shù)據(jù)結(jié)構(gòu) 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 */ }; //消息隊(duì)列特有的結(jié)構(gòu) struct msqid_ds {struct ipc_perm msg_perm; /* Ownership and permissions 各類IPC對(duì)象所共有的數(shù)據(jù)結(jié)構(gòu)*/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) 消息隊(duì)列中當(dāng)前所保存的字節(jié)數(shù) */msgqnum_t msg_qnum; /* Current number of messages in queue 消息隊(duì)列中當(dāng)前所保存的消息數(shù) */msglen_t msg_qbytes; /* Maximum number of bytes allowed in queue 消息隊(duì)列所允許的最大字節(jié)數(shù) */pid_t msg_lspid; /* PID of last msgsnd(2) */pid_t msg_lrpid; /* PID of last msgrcv(2) */ };消息隊(duì)列在內(nèi)核中的表示
?
消息在消息隊(duì)列中是以鏈表形式保存的,?每個(gè)節(jié)點(diǎn)的類型類似如下:
struct msq_Node {Type msq_type; //類型Length msg_len; //長度Data msg_data; //數(shù)據(jù)struct msg_Node *next; };消息隊(duì)列API
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int msgflg); int msgctl(int msqid, int cmd, struct msqid_ds *buf); int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);msgget
功能:用來創(chuàng)建和訪問一個(gè)消息隊(duì)列
int msgget(key_t key, int msgflg);參數(shù):
? key:?某個(gè)消息隊(duì)列的名字
? msgflg:由九個(gè)權(quán)限標(biāo)志構(gòu)成,如0644,它們的用法和創(chuàng)建文件時(shí)使用的mode模式標(biāo)志是一樣的(但是消息隊(duì)列沒有x(執(zhí)行)權(quán)限)
返回值:
? 成功返回消息隊(duì)列編號(hào),即該消息隊(duì)列的標(biāo)識(shí)碼;失敗返回-1
msgget調(diào)用關(guān)系圖
/** 示例1: 在msgflg處指定IPC_CREAT, 如果不存在該消息隊(duì)列, 則創(chuàng)建之**/ int main(int argc, char *argv[]) {//指定IPC_CREAT,如果不存在, 則創(chuàng)建消息隊(duì)列int msgid = msgget(1234, 0666|IPC_CREAT);if (msgid == -1)err_exit("msgget error");cout << "msgget success" << endl; } /** 示例2:IPC_CREAT|IPC_EXCL, 如果該消息隊(duì)列已經(jīng)存在, 則返回出錯(cuò) **/ int main(int argc, char *argv[]) {//指定IPC_EXCL, 如果已經(jīng)存在,則報(bào)告文件已經(jīng)存在(錯(cuò)誤)int msgid = msgget(1234, 0666|IPC_CREAT|IPC_EXCL);if (msgid == -1)err_exit("msgget error");cout << "msgget success" << endl; } /**示例3:將key指定為IPC_PRIVATE(值為0) 將key指定為IPC_PRIVATE之后,則msgget就一定會(huì)創(chuàng)建一個(gè)新的消息隊(duì)列, 而且每次創(chuàng)建的消息隊(duì)列的描述符都是不同的! 因此, 除非將MessageID(key)傳送給其他進(jìn)程(除非有關(guān)聯(lián)的進(jìn)程),其他進(jìn)程也無法使用該消息隊(duì)列(血緣fork除外) 因此, IPC_PRIVATE創(chuàng)建的消息隊(duì)列,只能用在與當(dāng)前進(jìn)程有關(guān)系的進(jìn)程中使用! **/ int main(int argc, char *argv[]) {//指定IPC_PRIVATEint msgid = msgget(IPC_PRIVATE, 0666|IPC_CREAT|IPC_EXCL);if (msgid == -1)err_exit("msgget error");cout << "msgget success" << endl; } /** 示例4: 僅打開消息隊(duì)列時(shí), msgflg選項(xiàng)可以直接忽略(填0), 此時(shí)是以消息隊(duì)列創(chuàng)建時(shí)的權(quán)限進(jìn)行打開 **/ int main(int argc, char *argv[]) {int msgid = msgget(1234, 0);if (msgid == -1)err_exit("msgget error");cout << "msgget success" << endl;cout << "msgid = " << msgid << endl; } //示例5:低權(quán)限創(chuàng)建,高權(quán)限打開 int main() {//低權(quán)限創(chuàng)建int msgid = msgget(0x255,0444 | IPC_CREAT);if (msgid < 0)err_exit("mesget error");elsecout << "Create Mes OK, msgid = " << msgid << endl;//高權(quán)限打開msgid = msgget(0x255,0644 | IPC_CREAT);if (msgid < 0)err_exit("mesget error");elsecout << "Create Mes OK, msgid = " << msgid << endl; }msgctl函數(shù)
功能:獲取/設(shè)置消息隊(duì)列的信息
int msgctl(int msqid, int cmd, struct msqid_ds *buf);參數(shù):
? ?msqid:?由msgget函數(shù)返回的消息隊(duì)列標(biāo)識(shí)碼
? ?cmd:是將要采取的動(dòng)作(見下)
?
cmd:將要采取的動(dòng)作(有三個(gè)可取值),分別如下:
/** 示例1: IPC_RMID, 刪除消息隊(duì)列 注意: 消息隊(duì)列并沒有運(yùn)用”引用計(jì)數(shù)”的功能 **/ int main() {int msgid = msgget(1234, 0);if (msgid == -1)err_exit("msgget error");if (msgctl(msgid, IPC_RMID, NULL) == -1)err_exit("msgctl IPC_RMID error");cout << "msgctl IPC_RMID success" << endl; } /** 示例2: IPC_STAT **/ int main() {int msgid = msgget(0x255, 0666|IPC_CREAT);if (msgid == -1)err_exit("msgget error");struct msqid_ds buf;if (msgctl(msgid,IPC_STAT,&buf) == -1)err_exit("msgctl error");printf("buf.msg_perm.mode = %o\n",buf.msg_perm.mode); //%o以八進(jìn)制打印printf("buf.__key = %x\n", buf.msg_perm.__key); //%x以十六進(jìn)制打印cout << "buf.__msg_cbytes = " << buf.__msg_cbytes << endl;cout << "buf.msg_qbytes = " << buf.msg_qbytes << endl;cout << "buf.msg_lspid = " << buf.msg_lspid << endl; } /** 實(shí)踐:IPC_SET,一般需要先獲取,然后再設(shè)置 **/ int main() {int msgid = msgget(0x255, 0);if (msgid == -1)err_exit("msgget error");//獲取消息隊(duì)列的屬性struct msqid_ds buf;if (msgctl(msgid,IPC_STAT,&buf) == -1)err_exit("msgctl error");//設(shè)置消息隊(duì)列的屬性buf.msg_perm.mode = 0600;if (msgctl(msgid, IPC_SET, &buf) == -1)err_exit("msgctl error");//獲取并打印bzero(&buf, sizeof(buf));if (msgctl(msgid, IPC_STAT, &buf) == -1)err_exit("msgctl IPC_STAT error");printf("mode = %o\n", buf.msg_perm.mode); }附-查看系統(tǒng)中的IPC對(duì)象
? ? ?ipcs
? ?刪除消息隊(duì)列
? ? ?ipcrm?-q?[msqid]
? 或 ?ipcrm?-Q?[key] #如果key不等于0的話
總結(jié)
以上是生活随笔為你收集整理的Linux IPC实践(4) --System V消息队列(1)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [WorldWind学习]12.Wavi
- 下一篇: 虚拟机linux挂载光盘显示:mount