Linux IPC实践(4) --System V消息队列(1)
消息隊列概述
? ?消息隊列提供了一個從一個進程向另外一個進程發送一塊數據的方法(僅局限于本機);
? ?每個數據塊都被認為是有一個類型,接收者進程接收的數據塊可以有不同的類型值.
? ?消息隊列也有管道一樣的不足:?(1)每個消息的最長字節數的上限(MSGMAX);?(2)系統中消息隊列的總條數也有一個上限(MSGMNI);?(3)每個消息隊列所能夠保存的總字節數是有上限的(MSGMNB)?.
?
查看系統限制
? ?cat?/proc/sys/kernel/msgmax? #最大消息長度限制
? ?cat?/proc/sys/kernel/msgmnb? #消息隊列總的字節數
? ?cat?/proc/sys/kernel/msgmni? #消息條目數
?
?
管道?vs.?消息隊列
管道 | 消息 |
流管道 | 有邊界 |
先進先出 | 可以后進先出 |
IPC對象數據結構
//內核為每個IPC對象維護一個數據結構 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 */ }; //消息隊列特有的結構 struct msqid_ds {struct ipc_perm msg_perm; /* Ownership and permissions 各類IPC對象所共有的數據結構*/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 msq_Node {Type msq_type; //類型Length msg_len; //長度Data msg_data; //數據struct msg_Node *next; };消息隊列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
功能:用來創建和訪問一個消息隊列
int msgget(key_t key, int msgflg);參數:
? key:?某個消息隊列的名字
? msgflg:由九個權限標志構成,如0644,它們的用法和創建文件時使用的mode模式標志是一樣的(但是消息隊列沒有x(執行)權限)
返回值:
? 成功返回消息隊列編號,即該消息隊列的標識碼;失敗返回-1
msgget調用關系圖
/** 示例1: 在msgflg處指定IPC_CREAT, 如果不存在該消息隊列, 則創建之**/ int main(int argc, char *argv[]) {//指定IPC_CREAT,如果不存在, 則創建消息隊列int msgid = msgget(1234, 0666|IPC_CREAT);if (msgid == -1)err_exit("msgget error");cout << "msgget success" << endl; } /** 示例2:IPC_CREAT|IPC_EXCL, 如果該消息隊列已經存在, 則返回出錯 **/ int main(int argc, char *argv[]) {//指定IPC_EXCL, 如果已經存在,則報告文件已經存在(錯誤)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就一定會創建一個新的消息隊列, 而且每次創建的消息隊列的描述符都是不同的! 因此, 除非將MessageID(key)傳送給其他進程(除非有關聯的進程),其他進程也無法使用該消息隊列(血緣fork除外) 因此, IPC_PRIVATE創建的消息隊列,只能用在與當前進程有關系的進程中使用! **/ 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: 僅打開消息隊列時, msgflg選項可以直接忽略(填0), 此時是以消息隊列創建時的權限進行打開 **/ 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:低權限創建,高權限打開 int main() {//低權限創建int msgid = msgget(0x255,0444 | IPC_CREAT);if (msgid < 0)err_exit("mesget error");elsecout << "Create Mes OK, msgid = " << msgid << endl;//高權限打開msgid = msgget(0x255,0644 | IPC_CREAT);if (msgid < 0)err_exit("mesget error");elsecout << "Create Mes OK, msgid = " << msgid << endl; }msgctl函數
功能:獲取/設置消息隊列的信息
int msgctl(int msqid, int cmd, struct msqid_ds *buf);參數:
? ?msqid:?由msgget函數返回的消息隊列標識碼
? ?cmd:是將要采取的動作(見下)
?
cmd:將要采取的動作(有三個可取值),分別如下:
/** 示例1: IPC_RMID, 刪除消息隊列 注意: 消息隊列并沒有運用”引用計數”的功能 **/ 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以八進制打印printf("buf.__key = %x\n", buf.msg_perm.__key); //%x以十六進制打印cout << "buf.__msg_cbytes = " << buf.__msg_cbytes << endl;cout << "buf.msg_qbytes = " << buf.msg_qbytes << endl;cout << "buf.msg_lspid = " << buf.msg_lspid << endl; } /** 實踐:IPC_SET,一般需要先獲取,然后再設置 **/ int main() {int msgid = msgget(0x255, 0);if (msgid == -1)err_exit("msgget error");//獲取消息隊列的屬性struct msqid_ds buf;if (msgctl(msgid,IPC_STAT,&buf) == -1)err_exit("msgctl error");//設置消息隊列的屬性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); }附-查看系統中的IPC對象
? ? ?ipcs
? ?刪除消息隊列
? ? ?ipcrm?-q?[msqid]
? 或 ?ipcrm?-Q?[key] #如果key不等于0的話
總結
以上是生活随笔為你收集整理的Linux IPC实践(4) --System V消息队列(1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [WorldWind学习]12.Wavi
- 下一篇: Matlab与OpenCV对应函数