1. 程式人生 > >Linux---程序間通訊IPC之訊息佇列

Linux---程序間通訊IPC之訊息佇列

**程序間通訊(IPC):**是指在不同程序之間傳播或交換資訊。
**IPC的方式:**通常有管道(無名管道、命名管道)、訊息佇列、訊號量、共享儲存、Socket、Streams等(Socket和Streams支援不同主機上的兩個程序IPC)
程序間通訊的目的:
1.資料傳輸:一個程序需要將它的資料發給另一個程序
**2.資源共享:**多個程序之間共享同樣的資源
**3.通知事件:**一個程序需要向另一個或一組程序傳送訊息,通知它(它們)傳送了啥(如程序終止要通知父程序)
**4.程序控制:**有些程序希望完全控制另一個程序的執行(如Debug程序),此時控制程序希望能夠攔截另一個程序的所有陷入和異常,並能夠及時知道它的狀態改變

**訊息佇列:**一種資料結構,佇列
訊息佇列提供了一個從一個程序向另一個進銷存傳送一塊資料的方法
訊息佇列也有管道一樣的不足,就是每個訊息的最大長度是有限的,每個訊息佇列總的位元組數是有上限的,系統上訊息佇列的總數是有上限的

系統能夠建立多少個訊息佇列?
cat/proc/sys/kernel/msgmni
每個訊息佇列能夠裝多少個位元組?
cat/proc/sys/kernel/msgmnb
佇列中每一條記錄最大是多少?
cat/proc/sys/kernel/max
這裡寫圖片描述

//訊息快取塊:一種資料結構,用於儲存資訊
struct msgbuf{
long channel;//通道號
char mtext[100];//訊息內容,100自定義
}

**通道:**通道並不真的存在,是一種分類,由訊息快取塊中的chnnel通道號決定,程序可以通過訊息佇列的通道來選擇對應型別的訊息佇列

訊息佇列基礎操作

1.建立/開啟訊息佇列

//建立新的或者開啟已經存在的訊息佇列
//返回值:-1 失敗,成功返回訊息佇列的識別符號id
int msgget(key_t key,int flag);

引數:key
每個訊息佇列都有一個唯一的識別符號id,也有一個唯一的關鍵字
函式會將key與已有關鍵字進行比較來判斷訊息佇列是否已經建立
生成key:

#include<sys/ipc.h>
#include<sys/types.h>
key_t ftok(const char* pathname,int proj_id);
//pathname是你指定的檔名,要求檔案必須存在,“.”這樣是當前目錄
//id是自序號,int型,只使用8bits,一般弄字母準沒錯
//返回值:-1 失敗,成功返回key值
//這個函式作用就是保證生成的key唯一

引數:flag

//操作訊息佇列許可權
//IPC_CREAT,建立新的訊息佇列,若已經存在,則開啟
//IPC_EXCL,IPC_CREAT一起用,如果要建立的訊息佇列已經存在,返回錯,這個就是全新的
//IPC_NOWAIT,讀寫訊息佇列讀不上時,不堵塞
//0,如果開啟檔案,檔案存在,輸0

程式碼實現:

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

int main()
{
	key_t key=ftok(".",'a');
	if(key == -1)
		perror("ftok"),exit(1);
	int id=msgget(key,IPC_CREAT|0644);
	if(id == -1)
		perror("msgget"),exit(1);
	printf("create success\n");
	printf("%d\n",id);
	return 0;
}

2.檢視訊息佇列

這裡寫圖片描述

3.刪除訊息佇列

命令:ipcrm -Q key值
這裡寫圖片描述
函式:msgctl(int msqid,int cmd,struct msqid_ds *buf);

#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
//msgctl對msqid標識的訊息佇列執行cmd操作
//返回值:0 成功,-1 失敗
int msgctl(int msqid,int cmd,struct msqid_ds *buf);

引數:

//msqid 訊息佇列識別符號
//cmd 
//{
//	IPC_STAT  讀取訊息佇列,存在buf
//	IPC_SET	  設定訊息佇列的值,值來自buf
//	IPC_RMID  從系統核心刪除訊息佇列,這時buf為0使用,即NULL
//}

這裡寫圖片描述
程式碼實現:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
int main()
{
	int id=msgget(0x61021ed2,0);
	if(id==-1)
	{
		perror("msgget");
		exit(1);
	}
	printf("訊息佇列存在\n");
	if(msgctl(id,IPC_RMID,0)==-1)
	{
		perror("msgctl");
		exit(1);
	}
	printf("msgctl success\n");
	return 0;
}

4.寫訊息佇列

函式:

#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
//將內容寫到(msgp指向的訊息佇列物件)裡,將(訊息佇列物件的內容)放進(msqid對應的訊息佇列)中
//返回值:0 成功,-1 失敗
int msgsnd(int msqid,const void* msgp,ssize_t msgsz,int msgflg);

引數:

//msqid 想要寫進的訊息佇列識別符號id
//msgp 臨時建立的訊息佇列結構體物件指標
//msgsz 寫入內容的大小,不包括通道號chennel,只是char mtext[ ]的大小
//msgflg  0 阻塞,IPC_NOWAIT 非阻塞

這裡寫圖片描述
程式碼實現:

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

struct msgbuf {
	long channel;
	char mtext[100];
};

int main( void )
{
	int id = msgget(0x61021ed2, 0); // 開啟訊息佇列,第二個引數為0
	if ( id == -1 ) perror("msgget"),exit(1);
	struct msgbuf mb;
	printf("channel:");
	scanf("%ld", &mb.channel);
	printf("text:");
	scanf("%s", mb.mtext);
	int r = msgsnd(id, &mb, strlen(mb.mtext), 0);
	if ( r == -1 ) perror("msgsnd"),exit(1);
}

5.讀訊息佇列

函式:

#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
//將(msqid對應的訊息佇列裡的內容)放到(msgp指向的訊息佇列結構體物件),從(msgp指向的物件)中讀取內容
//返回值:-1 失敗,成功返回訊息資料的長度
ssize_t msgrcv(int msqid,void *msgp,size_t msgsz,long msgtyp,int msgflg);

引數:

//msqid 想要讀取內容的訊息佇列識別符號id
//msgp 臨時建立的訊息佇列結構體物件指標
//magsz 讀取內容的大小,不包括通道號chennel,只是char mtext[ ]的大小
//mstyp 想讀取訊息所在通道號(channel)
//{
//	mstyp==0  返回佇列中第一個訊息
//	mstyp > 0 返回佇列中channle為mstyp的第一個訊息
//	mstyp < 0 返回佇列中channel小於或等於mstyp絕對值的訊息,如果有多個,取channel最小的訊息
//}

這裡寫圖片描述
程式碼實現:

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

struct msgbuf {

	long channel;
	char mtext[100];
};

int main( void )
{
	int id = msgget(0x61021ed2, 0); 
	//開啟訊息佇列,0x61021685是剛才建立的訊息佇列關鍵字
	//第二個引數為0,表示這是開啟訊息佇列而不是建立,即該訊息佇列存在
	if ( id == -1 )
		perror("msgget"),exit(1);
	struct msgbuf mb;
	printf("channel:");
	int channel;
	scanf("%d", &channel);

	ssize_t r=msgrcv(id,&mb,100,channel,IPC_NOWAIT);
	if(r == -1)
		perror("msgrcv"),exit(1);
	printf("%s\n",mb.mtext);
}

如果有什麼不對的地方,可以評論告訴我,望指導!