消息隊列的建立與讀寫ftok,msgget,msgsnd,msgrcv,指令ipcs,ipcrm 查看,刪除消息隊列

 

ipcs是Linux下顯示進程間通訊設施狀態的工具。能夠顯示消息隊列、共享內存和信號量的信息。對於程序員很是有用,普通的系統管理員通常用不到此指令。程序員

ipcs -查看系統使用的IPC隊列資源ide

ipcs -查看系統使用的IPC共享內存資源函數

ipcs -查看系統使用的IPC信號量資源工具

ipcs -a命令能夠查看當前使用的共享內存、消息隊列及信號量全部信息測試

ipcs -p命令能夠獲得與共享內存、消息隊列相關進程之間的消息ui

ipcs -u命令能夠查看各個資源的使用總結信息,其中能夠看到使用的信號量集的個數、信號量的個數,spa

以及消息隊列中當前使用的消息個數總數、佔用的空間字節數。命令行

默認不加參數時,使用的參數是 -(all,顯示全部)code

pcs -l命令能夠查看各個資源的系統限制信息,能夠看到系統容許的最大信號量集及信號量個數限制、最大的消息隊列中消息個數等信息。對象

yxg@k8s:~$ ipcs -l

 

------ Messages Limits --------
max queues system wide = 32000   //系統最多的消息隊列數量
max size of message (bytes) = 8192  //單個消息的最大字節數
default max size of queue (bytes) = 16384  //單個消息的最大字節數

 

------ Shared Memory Limits --------
max number of segments = 4096
max seg size (kbytes) = 18014398509465599
max total shared memory (kbytes) = 18014398442373116
min seg size (bytes) = 1

 

------ Semaphore Limits --------
max number of arrays = 32000
max semaphores per array = 32000
max semaphores system wide = 1024000000
max ops per semop call = 500
semaphore max value = 32767

 

這個限制能夠經過增長內核參數 semmni 的取值來解決,該參數定義了系統可以擁有的信號量集合的
總數。Linux 能夠動態調整大多數內核IPC 參數值的大小,也能夠靜態地修改

 

 

一、建立消息隊列

消息隊列是隨着內核的存在而存在的,每一個消息隊列在系統範圍內對應惟一的鍵值。要得到一個消息隊列的描述符,

只須要提供該消息隊列的鍵值便可,該鍵值一般由函數ftok返回。

key_t ftok(const char *pathname, int proj_id);

ftok函數根據pathname和proj_id這兩個參數生成惟一的鍵值。

pathname:must refer to an existing, accessible file,在系統中必定要存在,且進程有訪問權限。

proj_id:的取值範圍爲1-255 

#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h>

int main() { int i = 0; for(i=0;i<5;i++) { printf("key[%d] = %lu\n", i, ftok(".", i)); } return 0; }

 

ftok返回的鍵值能夠提供給函數msgget,

msgget根據這個鍵值建立一個新的消息隊列或者訪問一個已存在的消息隊列。

int msgget(key_t key, int msgflg);

參數key即爲ftok函數的返回值。msgflag是一個標誌參數。

如下是msgflg的可能取值:

IPC_CREAT:若是內核中不存在鍵值與key相等的消息隊列,則新建一個消息隊列;若是存在這樣的消息隊列,返回消息隊列的描述符。

IPC_EXCL:和IPC_CREAT一塊兒使用,若是對應鍵值的消息隊列已經存在,則出錯,返回-1

上述msgflg參數爲模式標誌參數,使用時須要與IPC對象存取權限(如0600)進行|運算來肯定消息隊列的存取權限.

 

若是用msgget建立了一個新的消息隊列對象時,則msqid_ds結構成員變量的值設置以下:

 

Ÿ        msg_qnum、msg_lspid、msg_lrpid、 msg_stime、msg_rtime設置爲0。

 

Ÿ        msg_ctime設置爲當前時間。

 

Ÿ        msg_qbytes設成系統的限制值。

 

Ÿ        msgflg的讀寫權限寫入msg_perm.mode中。

 

Ÿ        msg_perm結構的uid和cuid成員被設置成當前進程的有效用戶ID,gid和cuid成員被設置成當前進程的有效組ID。

 

 

注意:IPC_EXCL單獨使用是沒有任何意義的。

該函數若是調用成功返回一個消息隊列的描述符,不然返回-1

 

二、寫消息隊列

建立了一個消息隊列後,就能夠對消息隊列進行讀寫了。函數msgsnd用於向消息隊列發送(寫)數據。

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

msqid:函數向msgid標識的消息隊列發送一個消息

msgp:指向發送的消息。

msgsz:要發送消息的大小,不包含消息類型佔用的4個字節。

msgflg:操做標識位。能夠設置爲0或者IPC_NOWAIT。若是爲0,則當消息隊列已滿的時候,msgsnd將會阻塞,直到消息可寫進消息隊列;若是msgflg

爲IPC_NOWAIT,當消息隊列已滿的時候,msgsnd函數將不等待當即返回。

msgsnd函數成功返回0,失敗返回-1。常見錯誤碼有:EAGAIN,說明消息隊列已滿。

EIDRM:說明消息隊列已被刪除

EACCES:說明無權訪問消息隊列

 

#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <string.h>


//用戶自定義消息緩衝
struct mymsgbuf{ long msgtype; char buf[256]; }; int main() { struct mymsgbuf mymsgbuffer; int msglen = 0; int i = 0; int msgkey = 0; int qid = 0;//消息隊列標識符 //獲取鍵值
    msgkey = ftok(".", 11); qid = msgget(msgkey, IPC_CREAT|0660); printf("msgget return %d\n", qid); //填充消息結構,發送到消息隊列
    mymsgbuffer.msgtype = 4; strcpy(mymsgbuffer.buf, "manman"); msglen = sizeof(struct mymsgbuf) - 4; if (msgsnd(qid, &mymsgbuffer, msglen, 0) == -1) { perror("msgsnd error\n"); exit(1); } return 0; }

root@wilson-software:~/Project/xa# ./main
msgget return 0

執行程序以後,就向消息隊列放入了一條消息,經過指令ipcs查看:

------ Message Queues --------
key      msqid    owner    perms    used-bytes   messages
0x0b014424       0      root    660      256       1

 

 

三、讀消息隊列

消息隊列中放入數據後,其餘進程就能夠讀取其中的消息了。讀取消息的系統調用爲

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

參數含義:

msqid:消息隊列描述符

msgp:讀取的消息存儲到msgp指向的消息結構中

msgsz:消息緩衝區的大小

msgtyp:爲請求讀取的消息類型

msgtyp等於0 則返回隊列的最先的一個消息。
msgtyp大於0,則返回其類型爲mtype的第一個消息。
msgtyp小於0,則返回其類型小於或等於mtype參數的絕對值的最小的一個消息。

 

msgflg:操做標誌位。msgflg能夠爲IPC_NOWAIT, MSG_EXCEPT  ,MSG_NOERROR

0:表示忽略

IPC_NOWAIT:若是沒有知足條件的消息,調用當即返回,此時錯誤碼爲ENOMSG

若是不指定這個參數,那麼進程將被阻塞直到函數能夠從隊列中獲得符合條件的
消息爲止。若是一個client 正在等待消息的時候隊列被刪除,EIDRM 就會被返回若是進

程在阻塞等待過程當中收到了系統的中斷信號,EINTR 就會被返回。

MSG_EXCEPT :與msgtype配合使用,返回隊列中第一個類型不爲msgtype的消息

MSG_NOERROR:若是隊列中知足條件的消息內容大於所請求的msgsz字節,則把該消息截斷,截斷部分將被丟棄。

若是不指定這個參數,E2BIG 將被返回,而消息則留在隊列中不被

取出。當消息從隊列內取出後,相應的消息就從隊列中刪除了。

 可利用ipcrm -q 294912刪除該消息隊列。(294912爲msgqid)由於消息隊列是隨內核持續存在的,在程序中若不利用msgctl函數或在命令行用ipcrm命令顯式地刪除,該消息隊列就一直存在於系統中。另外信號量和共享內存也是隨內核持續存在的

在讀取前:

------ Message Queues --------
key      msqid    owner    perms    used-bytes    messages
0x0b014424   0     root    660      256       1

在讀取後

key     msqid   owner   perms   used-bytes   messages
0x0b014424   0     root    660     0        0

 

調用msgrcv函數的時候,成功會返回讀出消息的實際字節數,不然返回-1。

常見錯誤碼有:

E2BIG:  表示消息的長度大於msgsz

EIDRM:表示消息隊列已被刪除

EINVAL:說明msgqid無效或msgsz小於0

#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <string.h>


//用戶自定義消息緩衝
struct mymsgbuf{ long msgtype; char buf[256]; }; int main() { struct mymsgbuf mymsgbuffer; int msglen = 0; int i = 0; int msgkey = 0; int qid = 0;//消息隊列標識符 //獲取鍵值
    msgkey = ftok(".", 11); qid = msgget(msgkey, IPC_CREAT|0660); printf("msgget return %d\n", qid); 
    msglen = sizeof(struct mymsgbuf) - 4; 
 //上面的程序中發送的消息類型是4
 //注意,msgrcv的msgflg參數可設置msgrcv函數是不是阻塞的,經測試msgflg是0的狀況會阻塞,直到獲取到消息
if (msgrcv(qid, &mymsgbuffer, msglen, 4, 0) == -1) { perror("msgsnd error\n"); exit(1); } printf("get message:%s\n", mymsgbuffer.buf); return 0; }

 

運行結果:

root@wilson-software:~/Project/xa# ./main
msgget return 0
get message:manman

 +++++++++++++++++++++++++++++++++++++++++++++++++++++++

利用上面提到的msgrcv()對消息長度的處理,咱們可使用下面的方法來檢查隊列內
是存在符合條件的信息:
int peek_message( int qid, long type )
{
int result, length;
if((result = msgrcv( qid, NULL, 0, type, IPC_NOWAIT)) == -1)
{
if(errno == E2BIG)
return(TRUE);
}
return(FALSE);
}
這裏咱們將msgp 和msgsz 分別設爲NULL 和零。而後檢查函數的返回值,若是是E2BIG
則說明存在符合指定類型的消息。一個要注意的地方是IPC_NOWAIT 的使用,它防止了阻塞

相關文章
相關標籤/搜索