一、消息對列
消息隊列,是消息的鏈接表,存放在內核中。一個消息隊列由一個標識符(即隊列ID)來標識。
特點:
消息隊列是面向記錄的,其中的消息具有特定的格式以及特定的優先級。消息隊列獨立于發送與接收進程。進程終止時,消息隊列及其內容并不會被刪除。消息隊列可以實現消息的隨機查詢,消息不一定要以先進先出的次序讀取,也可以按消息的類型讀取。
原型:
#include <sys/msg.h>// 創建或打開消息隊列:成功返回隊列ID,失敗返回-1,flag是打開隊列的方式。int msgget(key_t key, int flag);// 添加消息:成功返回0,失敗返回-1,ptr是消息,size是消息的大小,flag是標志位。int msgsnd(int msqid, const void *ptr, size_t size, int flag);// 讀取消息:成功返回消息數據的長度,失敗返回-1,ptr是消息,size是消息的大小,type是消息的類型,flag是標志位。int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);// 控制消息隊列:成功返回0,失敗返回-1int msgctl(int msqid, int cmd, struct msqid_ds *buf);
在以下兩種情況下,msgget將創建一個新的消息隊列:
如果沒有與鍵值key相對應的消息隊列,并且flag中包含了IPC_CREAT標志位。
key參數為IPC_PRIVATE。
函數msgrcv在讀取消息隊列時,type參數有下面幾種情況:
type == 0,返回隊列中的第一個消息;
type > 0,返回隊列中消息類型為 type 的第一個消息;
type < 0,返回隊列中消息類型值小于或等于 type 絕對值的消息,如果有多個,則取類型值最小的消息。
可以看出,type值非 0 時用于以非先進先出次序讀消息。也可以把 type 看做優先級的權值。(其他的參數解釋,請自行Google之)
ftok函數
系統建立IPC通訊 (消息隊列、信號量和共享內存) 時必須指定一個ID值。通常情況下,該id值通過ftok函數得到。
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok( const char * fname, int id )
fname就是你指定的文件名(已經存在的文件名),一般使用當前目錄,如:
key_t key;
key = ftok(".", 1); 這樣就是將fname設為當前目錄。
id是子序號。雖然是int類型,但是只使用8bits(1-255)。
在一般的UNIX實現中,是將文件的索引節點號取出,前面加上子序號得到key_t的返回值。
如指定文件的索引節點號為65538,換算成16進制為0x010002,而你指定的ID值為38,換算成16進制為0x26,則最后的key_t返回值為0x26010002。
查詢文件索引節點號的方法是: ls -i
當刪除重建文件后,索引節點號由操作系統根據當時文件系統的使用情況分配,因此與原來不同,所以得到的索引節點號也不同。
接收代碼演示
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<string.h>
struct msgbuf
{long mtype; //信息的類型,必須大于0char mtext[128];//信息數據存放
};
int main()
{//1.huoqu duiliekey_t key;key=ftok(".",'z');struct msgbuf readbuf;printf("key =%x\n",key);//%x 是六進制的形式struct msgbuf sendbuf={988,"thank you for reach"};int msgid=msgget(key,IPC_CREAT|0777);//IPC_CREAT|0777分別表示創建隊列,和隊列的權限
// printf("ID=%x",msgid);if(msgid==-1){printf("creat fail\n");}msgrcv(msgid,&readbuf,sizeof(readbuf.mtext),888,0);// 如果最后一個為0,以默認的方式來讀,讀不到的話會堵塞msgsnd(msgid,&sendbuf,strlen(sendbuf.mtext),0);printf("read from que:%s\n",readbuf.mtext);msgctl(msgid,IPC_RMID,NULL);return 0;
}
發送代碼演示
<sys/msg.h>
#include<string.h>
struct msgbuf
{long mtype;char mtext[128];
};
int main()
{key_t key;key=ftok(".",'z');printf("key =%x\n",key);struct msgbuf sendbuf={888,"this is message from quen"};//888 是消息類型struct msgbuf readbuf;int msgid=msgget(key,IPC_CREAT|0777);if(msgid==-1){printf("creat fail\n");}msgsnd(msgid,&sendbuf,strlen(sendbuf.mtext),0);msgrcv(msgid,&readbuf,sizeof(readbuf.mtext),988,0);printf("return from get:%s\n",readbuf.mtext);msgctl(msgid,IPC_RMID,NULL);//IPC_RMID將消息隊列的鏈表從內核中移除。一般最后一個寫NULL,第一個是隊列id。return 0;
}
共享內存
共享內存(Shared Memory),指兩個或多個進程共享一個給定的存儲區。
特點:
共享內存是最快的一種 IPC,因為進程是直接對內存進行存取。因為多個進程可以同時操作,所以需要進行同步。信號量+共享內存通常結合在一起使用,信號量用來同步對共享內存的訪問。
思路:
(1)創建共享內存、若已經存在則直接打開
(2)映射將共享內存映射到進程獨自的內存空間
(3)數據交換
(4)釋放共享內存
(5)干掉共享內存
相關API
#include <sys/shm.h>// 創建或獲取一個共享內存:成功返回共享內存ID,失敗返回-1,共享內存的大小必須以兆對齊。int shmget(key_t key, size_t size, int flag);// (映射)連接共享內存到當前進程的地址空間:成功返回指向共享內存的指針,失敗返回-1void *shmat(int shm_id, const void *addr, int flag);// 斷開與共享內存的連接:成功返回0,失敗返回-1int shmdt(void *addr); // 控制共享內存的相關信息:成功返回0,失敗返回-1int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
當用shmget函數創建一段共享內存時,必須指定其 size;而如果引用一個已存在的共享內存,則將 size 指定為0 。
當一段共享內存被創建以后,它并不能被任何進程訪問。必須使用shmat函數連接該共享內存到當前進程的地址空間,連接成功后把共享內存區對象映射到調用進程的地址空間,隨后可像本地空間一樣訪問。
shmdt函數是用來斷開shmat建立的連接的。注意,這并不是從系統中刪除該共享內存,只是當前進程不能再訪問該共享內存而已。
shmctl函數可以對共享內存執行多種操作,根據參數 cmd 執行相應的操作。常用的是IPC_RMID(從系統中刪除該共享內存)。
寫端代碼
#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdlib.h>
#include <string.h>
//int shmget(key_t key, size_t size, int shmflg);
int main()
{int shmid;char* shmaddr;key_t key;key=ftok(".",1);shmaddr=(char*)malloc(1024*4);shmid=shmget(key,1024*4,IPC_CREAT|0666);//IPC_CREAT|0666 創建共享內存,注明內存權限可讀可寫if(shmid==-1){printf("creat fail\n");exit(-1);// 異常退出返回-1,正常退出返回0.}else{shmaddr=shmat(shmid,0,0);//第二個一般寫0,linux內核為我們自動的安排共享內存,第三個寫0,表示映射進來的共享內存是可讀可寫的。printf("shmat ok\n");strcpy(shmaddr,"I am handsome");//將內容寫入共享內存sleep(5);shmdt(shmaddr);//將映射的地址放入,卸載共享內存shmctl(shmid,IPC_RMID,0);//第三個參數用來存放卸載共享內存時產生的信息,不關心就寫0.IPC_RMID刪除共享內存printf("quit\n");}return 0;
}
讀端代碼
#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdlib.h>
#include <string.h>
//int shmget(key_t key, size_t size, int shmflg);
int main()
{int shmid;char* shmaddr;key_t key;key=ftok(".",1);shmaddr=(char*)malloc(1024*4);shmid=shmget(key,1024*4,0);// 讀的時候只獲取不創建所以最后的代碼寫0.if(shmid==-1){printf("creat fail\n");exit(-1);}else{shmaddr=shmat(shmid,0,0);printf("shmat ok\n");printf("data is %s\n",shmaddr);shmdt(shmaddr);printf("quit\n");shmctl(shmid,IPC_RMID,0);}return 0;
}
ipcs -m -------查看系統中有哪些共享內存
ipcrm -m + 共享內存ID號------刪除共享內存