linux c ipc機制
阿新 • • 發佈:2022-12-09
ipc
ipc 意思就是 程序間通訊機制的簡稱
在linux(centos)環境下 使用 ipcs
(資訊檢視),ipcrm
(刪除), ipcmk
(建立)
通過指令 ipcs
檢視, linux 支援的IPC機制有三種
- Message Queues: 訊息佇列
- Shared Memory Segments: 共享記憶體段
- Semaphore Arrays: 訊號量陣列
[root@process_comm#] ipcs ------ Message Queues -------- key msqid owner perms used-bytes messages 0x4201032a 0 root 666 184 2 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status ------ Semaphore Arrays -------- key semid owner perms nsems
訊息佇列
程式碼示例
程式碼如下: 使用 gcc -o recv ipc_que_recv.c
, gcc -o send ipc_que_send.c
編譯各自程式碼得到 recv
和 send
,分別執行
ipc_que_recv.c
#include <stdio.h> #include<errno.h> #include<string.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> int create_msg_queue() { /** * 該方法通過指定引數, 生成對應的 唯一key id標識 * extern key_t ftok (const char *__pathname, int __proj_id) __THROW; * __pathname: 存在的路徑名或者檔案,必須存在,否則返回錯誤 * __proj_id: 自己約定, 在unix中取值 1~255 */ key_t _key = ftok("temp113", 66); if(_key < 0) { printf("error to ftok \n"); return; } printf("ftok _key: 0x%0x \n", _key); /** * 該方法主要是為了根據 __key 查詢訊息佇列是否已經建立 * extern int msgget (key_t __key, int __msgflg) __THROW; * __key: 訊息佇列的物件的關鍵字(key) * __msgflg: 對條件進行判斷 * 0666: 第一位表示 條件判斷的處理方法 * 第二位表示 當前使用者的許可權, 讀.寫.可執行 * 第三位表示 group使用者組許可權 * 第四位表示 其它使用者的許可權 * ret: -1 失敗, 許可權被拒絕 * 0 成功 * 詳見: rttno-base.h * /proc/sys/kernel/msgmax 一個訊息的位元組大小 * /proc/sys/kernel/msgmnb 存放訊息佇列的總位元組數 * /proc/sys/kernel/msgmni 系統的訊息佇列數目 * 檢視系統支援訊息佇列數量, */ // int msgid = msgget(_key, IPC_CREAT | IPC_EXCL | 0666); int msgid = msgget(_key, IPC_CREAT | 0666); if(msgid < 0) { printf("error msgid %d \n", msgid); // errno 是記錄系統的最後一次錯誤程式碼 printf("%d : %s\n", errno, strerror(errno)); return 1; } printf("msgget msgid: 0x%0x \n", msgid); return msgid; } struct msgbuf { long mtype; unsigned char buff[92]; }; int main(int argc, char const *argv[]) { int msg_id = create_msg_queue(); struct msgbuf sbuf; sbuf.mtype = 0x01; int cnt = 0; while(1) { cnt ++; memset(sbuf.buff, 0x0, sizeof(sbuf.buff)); /** * 該函式為接收佇列訊息 * extern ssize_t msgrcv (int __msqid, void *__msgp, size_t __msgsz, long int __msgtyp, int __msgflg); * __msqid: msg_id * __msgp: 接收資料的緩衝區 * __msgsz: 接收資料緩衝區的大小 * __msgtyp: 接收資料的型別, 就是可以通過三四個以上的程序之間的通訊,用型別表示要傳送給指定的消費者 * 0, 函式不做型別檢查返回佇列中最舊的內容 * >0, 接收型別等於 __msgtyp 的第一個訊息 * <0, 接收型別等於或者小於msgtyp絕對值的第一個訊息 * __msgflg: 控制函式行為 * IPC_NOWAIT: 佇列為空,返回 ENOMSG( No message of desired type), 並將控制權交回呼叫函式的程序, 如果不指定, 那函式將一直處於阻塞狀態 * MSG_NOERROR: 如何函式取得的訊息長度大於 __msgsz, 將只返回 msgsz長度的資訊, 剩下的會被丟棄, 如果不指定這個函式, 將被返回狀態碼E2BIG(Argument list too long) * IPC_EXCEPT: 與msgtype配合使用返回佇列中第一個型別不為msgtype的訊息 * ret: -1, 讀取錯誤, 錯誤存在 error 中 * 否則返回實際讀取的資料長度 */ int rlen = msgrcv(msg_id, &sbuf, sizeof(sbuf.buff), 0x02, 0); if(rlen < 0) { printf("%d : %s", errno, strerror(errno)); return -1; } else { printf("[%d]%d:%0x %0x %0x %0x\n", cnt, rlen, sbuf.buff[0],sbuf.buff[20],sbuf.buff[90],sbuf.buff[91]); } usleep(1000*100); } return 0; }
ipc_que_send.c
#include <stdio.h> #include<errno.h> #include<string.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> int get_msg_queue() { key_t _key = ftok("temp113", 66); if(_key < 0) { printf("%d : %s",errno,strerror(errno)); return -1; } int msg_id = msgget(_key, IPC_CREAT); printf("msgid: %d \n", msg_id); return msg_id; } struct msgbuf { long mtype; unsigned char buff[92]; }; int main(int argc, char const *argv[]) { int msg_id = get_msg_queue(); struct msgbuf sbuf; memset(sbuf.buff, 'c', sizeof(sbuf.buff)); unsigned char cnt = 0; sbuf.mtype = 0x02; sbuf.buff[0] = 0x0; sbuf.buff[91] = 'a'; while (1) { sbuf.buff[0] = cnt; cnt++; /** * 該函式為向佇列傳送資料 * extern int msgsnd (int __msqid, const void *__msgp, size_t __msgsz, int __msgflg); * __msgflg: 控制傳送函式的行為, IPC_NOWAIT,如果訊息佇列已滿,訊息將不被寫入佇列,控制權返回呼叫函式的執行緒。如果不指定這個引數,執行緒將被阻塞直到訊息被可以被寫入。 * ret: 0 成功 * -1 errno */ int res = msgsnd(msg_id, &sbuf, sizeof(sbuf.buff), 0); printf("[%d] res %d, rlen %d res: %0x %0x %0x %0x \n", cnt, res, sizeof(sbuf.buff),sbuf.buff[0], sbuf.buff[20], sbuf.buff[60], sbuf.buff[91]); sleep(1); } return 0; }
實驗探索結論
1.當訊息佇列一旦建立之後, 他是存在於核心系統的, 不限於使用者態的程式, 也就是說使用者態的程式不管是java還是c, 不管是執行還是不執行, 不管是兩個程序還是更多的程序, 他都可以對訊息佇列進行收發資料的操作, 異或同一程序自發自收
2.訊息佇列在核心中的原始碼