訊息佇列
Linux系統中訊息佇列(Message Queue)是程序間通訊的一種方式,這種通訊機制的好處是可以傳輸指定型別(使用者可以自行定義)的資料,相同型別的資料根據到達順序在佇列中進行排隊。
不同型別的資料不能處於同一個佇列中,也就是說系統中可能存在多個訊息佇列,每個訊息佇列中的資料型別都是不同的,所以使用者打算讀取訊息佇列中的資料時也需要指定資料型別,才可以從儲存該型別資料的訊息佇列中讀取有效資料。
Linux系統中有很多訊息佇列,Linux系統是如何管理訊息佇列的呢,因為每個建立訊息佇列都具有唯一的鍵值key,程序可以透過指定訊息佇列的鍵值對指定的訊息佇列傳送資料,,且提供了一個shell命令:ipcs -a來檢視系統所有的ipc物件的訊息。
今日練習:要求程序A建立一條訊息佇列之後向程序B傳送SIGUSR1訊號,程序B收到該訊號之後開啟訊息佇列並把程序的PID作為訊息寫入到訊息佇列中,要求程序B在寫入訊息之後,發SIGUSR2訊號給程序A,程序A收到該訊號則從訊息佇列中讀取訊息並輸出訊息正文的內容。
目錄
- 訊息佇列
- 程序A
- 程序B
程序A
設計一個函式,透過msgget函式介面來獲取訊息佇列的ID,並向訊息佇列中接收字串
/*****************************************************************
*
* file name :main.c
* authour :yq_dyx@163.com
* date :2024.05.27
* function :設計一個函式,透過msgget函式介面來獲取訊息佇列的ID,並向訊息佇列中接收字串。
* note :為防止重複建立,需要先判斷共享記憶體和訊號量集是否存在。
* CopyRight (c) 2024 yq_dyx@163.com All Right Reseverd
*
******************************************************************/
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/msg.h>
#include <features.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
struct mymsg{
long mtype;
int mtext;
};
struct mymsg msg;
int msg_id;
//接收到訊號後的自定義處理函式的引數只能為訊號,所以想在此函式中呼叫其他引數需要定義為全域性變數
void sig_handler(int signo)
{
if(signo == SIGUSR2)
{
//用於接收訊息佇列裡面的內容,4:訊息佇列正文位元組數,0:是接收訊息選項,如果設定為0則是預設模式,當無指定型別訊息時阻塞
msgrcv(msg_id,&msg,4,1,0);
printf("msg.mtext is %d\n",msg.mtext);
}
}
int main()
{
//獲取“.”檔案的key值
key_t key = ftok(".",3);
if(-1 == key)
{
fprintf(stderr,"msgget failed,errno is %d,%s\n",errno,strerror(errno));
return -1;
}
//獲取訊息佇列的ID,如果沒有建立訊息佇列則建立
msg_id = msgget(key,IPC_CREAT|0644);
if(-1 == msg_id)
{
fprintf(stderr,"msgget failed,errno is %d,%s\n",errno,strerror(errno));
return -1;
}
//訊息佇列函式介面提供的結構體,mtype是訊息型別,mtext是訊息內容
struct mymsg msg;
msg.mtype = 1;
//kill是系統提供可以向另一個程序傳送訊號,getpid()是獲取程序號,+1是為了獲取另一個通訊程序的ID,因為那個程序在程序A後立馬建立則+1
kill(getpid()+1,SIGUSR1);
while(1)
//對於收到的訊號進行自定義處理,設計一個子函式,用於接受到訊號後此程序的行為
signal(SIGUSR2,sig_handler);
return 0;
}
ftok()函式可以把一個指定路徑的檔案和一個指定的專案id轉換為一個system-V IPC物件使用的鍵值key。
此key用於msgget來獲取訊息佇列的ID。
程序B
設計一個函式,透過msgget函式介面來獲取訊息佇列的ID,並向訊息佇列中傳送字串。
/*****************************************************************
*
* file name :main.c
* authour :yq_dyx@163.com
* date :2024.05.27
* function :設計一個函式,透過msgget函式介面來獲取訊息佇列的ID,並向訊息佇列中傳送字串。
* note :為防止重複建立,需要先判斷共享記憶體和訊號量集是否存在。
* CopyRight (c) 2024 yq_dyx@163.com All Right Reseverd
*
******************************************************************/
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/msg.h>
#include <features.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
struct mymsg{
long mtype;
int mtext;
};
struct mymsg msg;
int msg_id;
//接收到訊號後的自定義處理函式的引數只能為訊號,所以想在此函式中呼叫其他引數需要定義為全域性變數
void sig_handler(int signo)
{
printf("成功\n");
//mtype指的是訊息型別,必須是一個大於0的正整數
msg.mtype = 1;
msg.mtext = getpid();
printf("msg.mtext is %d\n",msg.mtext);
}
int main()
{
//獲取“.”檔案的key值
key_t key = ftok(".",3);
if(-1 == key)
{
fprintf(stderr,"msgget failed,errno is %d,%s\n",errno,strerror(errno));
return -1;
}
//獲取訊息佇列的ID,如果沒有建立訊息佇列則建立
msg_id = msgget(key,IPC_CREAT|0644);
if(-1 == msg_id)
{
fprintf(stderr,"msgget failed,errno is %d,%s\n",errno,strerror(errno));
return -1;
}
while(1)
{
//對於收到的訊號進行自定義處理,設計一個子函式,用於接受到訊號後此程序的行為
signal(SIGUSR1,sig_handler);
//用於傳送訊息佇列裡面的內容,4:訊息佇列正文位元組數,0:msgsnd函式的第四個引數msgflg指的是訊息佇列的標誌,如果該標誌設定為IPC_NOWAIT,則表示不阻塞,此時如果待寫入的訊息的長度大於訊息佇列剩餘空間,則直接返回並報錯。
msgsnd(msg_id,&msg,4,0);
//kill是系統提供可以向另一個程序傳送訊號,getpid()是獲取程序號,+1是為了獲取另一個通訊程序的ID,因為那個程序在程序A後立馬建立則+1
kill(getpid()-1,SIGUSR2);
}
return 0;
}