Linux進程間通信——消息隊列

2020-11-07 lee哥的伺服器開發

概念

什麼是消息隊列?

  • 消息隊列亦稱報文隊列,也叫做信箱。是Linux的一種通信機制,這種通信機制傳遞的數據具有某種結構,而不是簡單的字節流。
  • 消息隊列的本質其實是一個內核提供的鍊表,內核基於這個鍊表,實現了一個數據結構
  • 向消息隊列中寫數據,實際上是向這個數據結構中插入一個新結點;從消息隊列匯總讀數據,實際上是從這個數據結構中刪除一個結點
  • 消息隊列提供了一個從一個進程向另外一個進程發送一塊數據的方法
  • 消息隊列也有管道一樣的不足,就是每個數據塊的最大長度是有上限的,系統上全體隊列的最大總長度也有一個上限

隊列工作機制



用戶消息緩衝區

無論發送進程還是接收進程,都需要在進程空間中用消息緩衝區來暫存消息。該消息緩衝區的結構定義如下

struct msgbuf { long mtype; /* 消息的類型 */ char mtext[1]; /* 消息正文 */};

  • 可通過mtype區分數據類型,同過判斷mtype,是否為需要接收的數據
  • mtext[]為存放消息正文的數組,可以根據消息的大小定義該數組的長度

創建消息隊列

通過msgget創建消息隊列
函數原型如下

#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgget(key_t key, int msgflg);

參數

  • key: 某個消息隊列的名字
  • msgflg:由九個權限標誌構成,用法和創建文件時使用的mode模式標誌是一樣的,這裡舉兩個來說明

IPC_CREAT 如果消息隊列對象不存在,則創建之,否則則進行打開操作IPC_EXCL 如果消息對象不存在則創建之,否則產生一個錯誤並返回

返回值

  • 成功msgget將返回一個非負整數,即該消息隊列的標識碼;
  • 失敗則返回「-1」

那麼如何獲取key值?

  • 通過宏定義key值
  • 通過ftok函數生成key值,這裡就不具體介紹ftok函數用法

Linuxc/c++伺服器開發高階視頻,電子書學習資料後臺私信【架構】獲取


添加信息到消息隊列

向消息隊列中添加數據,使用到的是msgsnd()函數
函數原型如下

int msgsnd(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);

參數

  • msgid: 由msgget函數返回的消息隊列標識碼
  • msg_ptr:是一個指針,指針指向準備發送的消息,
  • msg_sz:是msg_ptr指向的消息長度,消息緩衝區結構體中mtext的大小,不包括數據的類型
  • msgflg:控制著當前消息隊列滿或到達系統上限時將要發生的事情
    如:
    msgflg = IPC_NOWAIT 表示隊列滿不等待,返回EAGAIN錯誤

返回值

  • 成功返回0
  • 失敗則返回-1

從消息隊列中讀取消息

從消息隊列中讀取消息,我們使用msgrcv()函數,
函數原型如下

int msgrcv(int msgid, void *msg_ptr, size_t msgsz, long int msgtype, int msgflg);

參數

  • msgid: 由msgget函數返回的消息隊列標識碼
  • msg_ptr:是一個指針,指針指向準備接收的消息,
  • msgsz:是msg_ptr指向的消息長度,消息緩衝區結構體中mtext的大小,不包括數據的類型
  • msgtype:它可以實現接收優先級的簡單形式
    msgtype=0返回隊列第一條信息
    msgtype>0返回隊列第一條類型等於msgtype的消息 
    msgtype<0返回隊列第一條類型小於等於msgtype絕對值的消息
  • msgflg:控制著隊列中沒有相應類型的消息可供接收時將要發生的事
    msgflg=IPC_NOWAIT,隊列沒有可讀消息不等待,返回ENOMSG錯誤。
    msgflg=MSG_NOERROR,消息大小超過msgsz時被截斷

注意

msgtype>0且msgflg=MSC_EXCEPT,接收類型不等於msgtype的第一條消息

返回值

  • 成功返回實際放到接收緩衝區裡去的字符個數
  • 失敗,則返回-1

消息隊列的控制函數

函數原型

int msgctl(int msqid, int command, strcut msqid_ds *buf);

參數

  • msqid: 由msgget函數返回的消息隊列標識碼
  • command:是將要採取的動作,(有三個可取值)分別如下


注意:若選擇刪除隊列,第三個參數傳NULL
返回值
如果操作成功,返回「0」;如果失敗,則返回「-1」

查看消息隊列

  • 查看消息隊列
    ipcs -q 命令查看已經創建的消息隊列,包括他的key值信息,id信息,擁有者信息,文件權限信息,已使用的字節數,和消息條數。
  • ipcrm -Q加消息隊列的key值,或來刪除一個消息隊列。

舉一個例子,父進程寫消息(先寫發送的數據類型,再寫數據),子進程收消息類型為1的消息

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <errno.h>#define MSGKEY 123//消息的數據結構是以一個長整型成員變量開始的結構體struct msgstru{ long msgtype; char msgtext[2048];};int main(){ struct msgstru msgs; char str[256]; int msg_type; int ret_value; int msqid; int pid; //檢查消息隊列是否存在 msqid = msgget(MSGKEY, IPC_EXCL);//(鍵名,權限) if (msqid < 0) { //創建消息隊列 msqid = msgget(MSGKEY, IPC_CREAT | 0666); if (msqid <0) { printf("failed to create msq | errno=%d [%s]\n", errno, strerror(errno)); exit(-1); } } pid = fork();//創建子進程 if (pid > 0) { //父進程 while (1) { printf("input message type:\n");//輸入消息類型 scanf("%d", &msg_type); if (msg_type == 0) break; printf("input message to be sent:\n");//輸入消息信息 scanf("%s", str); msgs.msgtype = msg_type; strcpy(msgs.msgtext, str); //發送消息隊列(sizeof消息的長度,而不是整個結構體的長度) ret_value = msgsnd(msqid, &msgs, sizeof(msgs.msgtext), IPC_NOWAIT); if (ret_value < 0) { printf("msgsnd() write msg failed,errno=%d[%s]\n", errno, strerror(errno)); exit(-1); } } } else if (pid == 0) { //子進程 while (1) { msg_type = 1;//接收的消息類型為1 msgs.msgtype = msg_type; //發送消息隊列(sizeof消息的長度,而不是整個結構體的長度) ret_value = msgrcv(msqid, &msgs, sizeof(msgs.msgtext), msgs.msgtype, IPC_NOWAIT); if (ret_value > 0) { printf("read msg:%s\n", msgs.msgtext); } } } else { printf("fork error\n"); //刪除消息隊列 msgctl(msqid, IPC_RMID, 0); exit(1); } return 0;}

運行結果

相關焦點

  • python筆記44:進程間通信機制-消息隊列
    主要內容:小目標:掌握進程間通信方式主要內容:消息隊列一個問題:父子進程之間變量不共享,他們之間如何進行通信?1.消息隊列消息隊列是進程間通信的一種方式,它基於系統提供的機制實現;使用方式:from multiprocessing import Queue方法說明:
  • 你未必知道 Linux作業系統進程間通信
    (一)無名管道,它具有幾個特點:  1) 管道是半雙工的,只能支持數據的單向流動;兩進程間需要通信時需要建立起兩個管道;  2) 無名管道使用pipe()函數創建,只能用於父子進程或者兄弟進程之間;  3) 管道對於通信的兩端進程而言,實質上是一種獨立的文件,只存在於內存中;  4) 數據的讀寫操作:一個進程向管道中寫數據,所寫的數據添加在管道緩衝區的尾部
  • 6種Linux進程間的通信方式
    但很多情況下進程間需要互相通信,來完成系統的某項功能。進程通過與內核及其它進程之間的互相通信來協調它們的行為。進程通信的應用場景數據傳輸:一個進程需要將它的數據發送給另一個進程,發送的數據量在一個字節到幾兆字節之間。共享數據:多個進程想要操作共享數據,一個進程對共享數據的修改,別的進程應該立刻看到。
  • Linux內核-進程間通信組件的實現
    ,進程間通信,虛擬文件系統和網絡接口。由於不用的用戶進程擁有不同的進程空間,因此進程間的通信要藉助於內核的中轉來實現。一般情況下,當一個進程等待硬體操作完成時,會被掛起。當硬體操作完成,進程被恢復執行,而協調這個過程的就是進程間的通信機制。三、進程間通信進程間通信主要用於控制不同進程之間在用戶空間的同步、數據共享和交換。
  • Linux後臺伺服器開發——Linux下進程間通信的方式有哪些?
    Linux下進程間通信的方式有:管道消息隊列信號信號量共享存儲套接字一、管道管道是半雙工的,數據只能向一個方向流動;需要雙方通信時,需要建立起兩個管道>FIFO命名管道詳情參閱:https://blog.csdn.net/qq_41453285/article/details/89472561匿名管道,由於沒有名字,只能用於親緣關係的進程間通信。
  • 作業系統 - 消息傳遞系統中的進程間通信
    這要求了進程間共享一塊內存區域,並且可以讓應用編程人員通過代碼訪問和操縱這塊共享內存。達到相同效果的另一種方法是,作業系統提供用於進程之間通過消息傳遞的工具來實現相互通信的。消息傳遞提供了一種機制,這種機制允許進程在不分享相同地址空間的情況下,通訊和同步他們的行為。這在分布式系統中特別有用,因為通訊的進程為了連結在網絡中的不同計算機上。
  • linux環境高級編程-高級IO和進程間通信詳解
    進程間通信介紹了基本進程間通信機制,包括兩大類:進程間數據共享:管道,FIFO,消息隊列和共享存儲進程間數據同步:信號量網絡進程間通信介紹網絡間的進程通信機制:套接字。高級進程間通信高級進程間通信提供一種可以在進程間傳遞文件描述符的機制,包括STREAMS管道和unix域套接字需要C/C++ Linux伺服器架構師學習資料後臺私信「資料」(資料包括C/C++,Linux,
  • linux進程間通信——深入理解linux信號量
    信號燈信號燈與其他進程間通信方式不大相同,它主要提供對進程間共享資源訪問控制機制。相當於內存中的標誌,進程可以根據它判定是否能夠訪問某些共享資源(臨界區,類似於互斥鎖),同時,進程也可以修改該標誌。除了用於訪問控制外,還可用於進程同步。1.
  • python核心編程之linux系統進程間通信-Queue
    進程間通信-QueueProcess之間有時需要通信,作業系統提供了很多機制來實現進程間的通信。1.:3消息列隊已滿,現有消息數量:3消息1消息2消息3說明初始化Queue()對象時(例如:q=Queue()),若括號中沒有指定最大可接收的消息數量,或數量為負值,那麼就代表可接受的消息數量沒有上限(直到內存的盡頭);Queue.qsize():返回當前隊列包含的消息數量;Queue.empty
  • 進程間的五種通信方式介紹
    進程間通信又叫IPC (InterProcess Communication)是指在不同進程之間傳播或交換信息。IPC的方式通常有管道(包括無名管道和命名管道)、消息隊列、信號量、共享存儲、Socket。 Socket支持不同主機上的兩個進程IPC。
  • 進程間通信之信號量semaphore--linux內核剖析
    常用於線程間同步。 而SYSTEM V信號量則是一個或多個信號量的集合,它對應的是一個信號量結構體,這個結構體是為SYSTEM V IPC服務的,信號量只不過是它的一部分。常用於進程間同步。time_t sem_otime; /* 最後一次成功修改信號量數組的時間 */ time_t sem_ctime; /* 成功創建時間 */};其中ipc_perm 結構是內核給每個進程間通信對象維護的一個信息結構
  • 消息隊列詳解
    1,什麼是消息隊列 消息隊列(message queue)是進程間通信或同一進程的不同線程間的通信方式。),ChannelQueue(隊列),Message(消息體)4,消息模式 點對點模型用於消息生產者和消息消費者之間點到點的通信。
  • 多進程編程 - 消息隊列
    消息隊列是在兩個進程之間傳遞二進位數據的一種簡單有效的方式。每個數據塊都有一個特定的類型,接收方可以根據類型來有選擇地接受數據,而不一定像管道和命名管道那樣必須以先進先出的方式接受數據。Linux消息隊列的API都定義在sys/msg.h頭文件中,包括4個系統調用:msgget、msgsnd、msgrcv、msgctlmsgget系統調用msgget系統調用創建一個消息隊列,或者獲取一個已有的消息隊列。
  • swoole教程第一節:進程管理模塊-(消息隊列)
    Error: Invalid argument[22] in /home/sun/learn/swoole/process/demo.php on line 20Worker Exit, PID=3668Worker Exit, PID=3667這就是我的報錯,我看這個錯誤,發現第一個進程是完美執行的,和預先想的一樣,錯誤出在主進程第二次發送消息到消息隊列時出現的,主進程的數據發送出錯了
  • python筆記45:進程間通信機制-共享內存
    主要內容:小目標:掌握進程間通信方式主要內容:共享內存一個問題:有沒有一種方式,多個進程可以同時訪問修改同一個變量?實現原理:為了在多個進程間交換信息,內核提供一種映射機制;多個進程就可以直接讀寫一塊公共內存地址而不需要進行數據的拷貝;優點:速度快,使用方便缺點:同步問題
  • 作業系統 - 進程間通信
    在作業系統中並發的執行進程可以是獨立的進程,也可以是合作進程。如果進程不需要與系統中其他進程共享數據的的進程是獨立的independent。需要與系統中其他進程相互有影響的進程是合作的cooperating。很明顯與其他進程共享數據的任意進程都是一個cooperationg進程。
  • 即時通訊小程序-IPC之消息隊列
    消息隊列上次說到了進程間通信的管道,不過匿名管道有個缺點就是,只能做到有親緣關係的進程間通信,所以今天學習一個新的進程間通信方式——消息隊列。消息隊列提供了一個從一個進程向另外一個進程發送一塊數據的方法每個數據塊都被認為是有一個類型,接收者進程接收的數據塊可以有不同的類型值消息隊列也有管道一樣的不足,就是每個數據塊的最大長度是有上限的,系統上全體隊列的最大總長度也有一個上限
  • 基於VxWorks的全IP開發平臺進程通信處理機制
    模塊主要實現相同處理器內和不同處理器之間進程間通信功能,進程間的通信主要依靠調度任務從郵箱中接收消息,並把消息派發到各個進程的消息隊列來實現,底層協議類型包括可靠通信協議(TCP)和不可靠通信協議(UDP)。關鍵詞:嵌入式作業系統;網絡處理器單元;消息隊列;Vxworks引言 隨著IP技術的迅速發展,「Everything over IP」的觀念已深入人心。
  • linux用戶空間與內核空間通信——Netlink通信機制
    一:什麼是Netlink通信機制Netlink是linux提供的用於內核和用戶態進程之間的通信方式但是注意雖然Netlink主要用於用戶空間和內核空間的通信,但是也能用於用戶空間的兩個進程通信。只是進程間通信有其他很多方式,一般不用Netlink。
  • Linux 進程必知必會
    Linux 進程間通信Linux 進程間的通信機制通常被稱為 Internel-Process communication,IPC 下面我們來說一說 Linux 進程間通信的機制,大致來說,Linux 進程間的通信機制可以分為 6 種