Linux進程間通信之消息隊列

来源:http://www.cnblogs.com/haoguoeveryone/archive/2016/10/06/haoguo_1.html
-Advertisement-
Play Games

本文首先從巨集觀的角度對進程間的通信方式之一,消息隊列進行闡述,然後以代碼實例對消息隊列進行更近一步的闡述,最後試著暢想消息隊列的潛在應用 ...


本文依據以下思路展開,首先從巨集觀上闡述消息隊列的機制,然後以具體代碼為例進一步闡述該機制,最後試著暢想一下該通信機制潛在的應用。

 

消息隊列是在兩個不相關進程間傳遞數據的一種簡單、高效方式,她獨立於發送進程、接受進程而存在。

 

 

圖1 消息隊列通信機制示意圖

 首先從巨集觀的角度瞭解一下消息隊列的工作機制。因為消息隊列獨立於進程而存在,為了區別不同的消息隊列,需要以key值標記消息隊列,這樣兩個不相關進程可以通過事先約定的key值通過消息隊列進行消息收發。例如進程A向key消息隊列發送消息,進程B從Key消息隊列讀取消息。在這一過程中主要涉及到四個函數:

#include <sys/msg.h> # 消息隊列相關函數及數據結構頭文件

int msgctl(int msqid, int cmd, struct msqid_ds *buf);# 控制消息隊列函數

int msgget(key_t key, int msgflg); # 創建消息隊列,key值唯一標識該消息隊列

int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg);# 接收消息

int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflg);# 發送消息

下麵結合代碼實例,對上述過程進行分析(具體分析見代碼註釋)

# msg1.c 接收端

#include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/msg.h> # 包含消息隊列相關函數及數據結構的頭文件 struct my_msg_st { long int my_msg_type; char some_text[BUFSIZ]; };# 消息格式 int main() { int running = 1; int msgid; struct my_msg_st some_data; long int msg_to_receive = 0; msgid = msgget((key_t)1234, 0666 | IPC_CREAT);# 創建標識符為key = 1234 的消息隊列,註意發送端與接收端該值的一致性 if (msgid == -1) { fprintf(stderr, “msgget failed with error: %d\n”, errno); exit(EXIT_FAILURE); }# 錯誤處理:msgget調用成功返回消息隊列標識符,調用失敗返回-1 while(running) { if (msgrcv(msgid, (void *)&some_data, BUFSIZ,msg_to_receive, 0) == -1) { # 從消息隊列接收消息,如果接收失敗執行if語句並退出 fprintf(stderr, “msgrcv failed with error: %d\n”, errno); exit(EXIT_FAILURE); } printf(“You wrote: %s”, some_data.some_text); if (strncmp(some_data.some_text, “end”, 3) == 0) { # 如果接收到文本含有“end”,將running設置為0,效果是:退出while迴圈 running = 0; } } if (msgctl(msgid, IPC_RMID, 0) == -1) { # 刪除消息隊列,如果刪除失敗執行if語句並退出 fprintf(stderr, “msgctl(IPC_RMID) failed\n”); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
# msg2.c 發送端

#include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/msg.h> #define MAX_TEXT 512 struct my_msg_st { long int my_msg_type; char some_text[MAX_TEXT]; };# 消息格式,與接收端一致 int main() { int running = 1; struct my_msg_st some_data; int msgid; char buffer[BUFSIZ]; msgid = msgget((key_t)1234, 0666 | IPC_CREAT);# 創建消息標識符key = 1234的消息隊列。如果該隊列已經存在,則直接返回該隊列的標識符,以便向該消息隊列收發消息 if (msgid == -1) { fprintf(stderr, “msgget failed with error: %d\n”, errno); exit(EXIT_FAILURE); }# 錯誤處理,同接收者msg1 while(running) { printf(“Enter some text: “); fgets(buffer, BUFSIZ, stdin);# 由控制台輸入文本,並將其存放在buffer之中 some_data.my_msg_type = 1;# 類型填充,在本例中沒有特別含義 strcpy(some_data.some_text, buffer);# 將buffer數據複製到some_text之中 if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1) { # 向消息隊列發送消息,如果發送失敗執行if語句並退出 fprintf(stderr, “msgsnd failed\n”); exit(EXIT_FAILURE); } if (strncmp(buffer, “end”, 3) == 0) {# 如果發送的“end”,則在發送“end”之後,退出while,結束程式 running = 0; } } exit(EXIT_SUCCESS); }

 以下是在控制台模擬的結果:

$ ./msg2

Enter some text: hello

Enter some text: How are you today?

Enter some text: end

$ ./msg1

You wrote: hello

You wrote: How are you today?

You wrote: end

$

消息隊列潛在應用

圖2 消息隊列在守護進程中的應用

如圖2所示,假如有三個圖形界面程式,他們分別對應進程1、進程2、進程3。這三個應用程式都需要滑鼠、鍵盤操作,如果在每個進程都加入捕獲滑鼠、鍵盤操作的代碼,那麼一共需要三份這樣的代碼,有點浪費資源(記憶體空間)。如果我們將捕獲滑鼠、鍵盤操作的代碼獨立出來做成一個單獨的進程,該進程向特定的消息隊列發送捕獲的滑鼠、鍵盤操作,當前激活圖像程式可以從該消息隊列中提取相應的滑鼠、鍵盤操作,然後據此執行後續的指令。以這種方式,能夠將不同應用程式中,共性的部分提取出來,從而簡化應用程式的設計和設計更加優化的共性處理程式。

 

消息隊列潛在應用之升華

 

處理程式共性部分的一些方法:

庫:通用的一些功能實現為庫函數,對外提供定義良好的藉口;應用程式在應用這些功能的時候,只需調用相應介面即可。

守護進程:將應用程式的共性部分提出出來實現為守護進程,通過某種通信機制實現守護進程與應用程式的信息交互。

 

參考資料:《Linux程式設計 第四版》

 

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ipcs ipcs m 查看系統中已經存在的共用記憶體 shmid :共用記憶體的id perms :permission nattch :number attatch ipcs q 查看系統中現有的消息隊列 used byte: 隊列的大小 message : 隊列中消息的條數 ipcs s 查看系統 ...
  • 管道是Linux的十種文件類型之一,使用管道通信本質上還是以文件作為通信的媒介 有名管道+無名管道=管道 有名管道(FIFO文件):就是 有文件名的管道, 可以用於任意兩個進程間的通信 無名管道(pipe文件):就是沒有文件名的管道, 只能用於父子進程之間的通信 mkfifo 創建有名管道,管道不能 ...
  • Linux中, 系統為每個系統都維護了三種計時器,分別為: 真實計數器, 虛擬計時器以及實用計時器, 一般情況下都使用真實計時器 getitimer()/setitimer() which //具體的計時器類型 1. ITIMER_REAL :真實計時器 統計進程消耗的真實時間 通過定時產生SIGA ...
  • 信號本質上就是一個軟體中斷,它既可以作為兩個進程間的通信的方式, 更重要的是, 信號可以終止一個正常程式的執行, 通常被用於處理意外情況 , 信號是非同步的, 也就是進程並不知道信號何時會到達 $kill 9 3390 向PID為3390的進程發送編號為9的信號= 一個兩個進程間通信的方式之一 一共6 ...
  • 環境:虛擬機VMware10 首先瞭解幾個註意的地方: 一、分區類型: 1、主分區:最多只能有四個; 2、擴展分區:最多只能有一個,且主分區加上擴展分區最多只能有四個,擴展分區不能寫入數據,只能包含邏輯分區 3、邏輯分區:可以寫入數據和格式化 舉個例子如圖: 其中1、2、3為主分區,4為擴展分區,5 ...
  • 向一個/一些進程發送一個信號 $kill [ slL] [...] 指定發送的信號,可以使用名稱或者信號編號 列出當前系統的所有信號 ...
  • 概述 多進程代碼區模型(其他區參見copy on write): getpid()、getppid() getuid()、geteuid() getgid(),getegid() fork() include include if(0==pid){ int res=execl("./proc","p ...
  • ps
    查看當前終端所啟動的進程, 不加選項只查看當前終端的進程 ps aux 查看所有進程,ps aux是BSD syntax,ps aux是standard syntax, 但二者的意義完全不同= $man ps ps ef 以全格式的方式顯示所有進程(every)查看當前終端所啟動的進程, 不加選項只 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...