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

来源:http://www.cnblogs.com/daochong/archive/2017/06/12/6993231.html
-Advertisement-
Play Games

下麵來說說如何用不用消息隊列來進行進程間的通信,消息隊列與命名管道有很多相似之處。有關命名管道的更多內容可以參閱我的另一篇文章:Linux進程間通信——使用命名管道 一、什麼是消息隊列 消息隊列提供了一種從一個進程向另一個進程發送一個數據塊的方法。 每個數據塊都被認為含有一個類型,接收進程可以獨立地 ...


下麵來說說如何用不用消息隊列來進行進程間的通信,消息隊列與命名管道有很多相似之處。有關命名管道的更多內容可以參閱我的另一篇文章:Linux進程間通信——使用命名管道   一、什麼是消息隊列 消息隊列提供了一種從一個進程向另一個進程發送一個數據塊的方法。  每個數據塊都被認為含有一個類型,接收進程可以獨立地接收含有不同類型的數據結構。我們可以通過發送消息來避免命名管道的同步和阻塞問題。但是消息隊列與命名管道一樣,每個數據塊都有一個最大長度的限制。   Linux用巨集MSGMAX和MSGMNB來限制一條消息的最大長度和一個隊列的最大長度。   二、在Linux中使用消息隊列 Linux提供了一系列消息隊列的函數介面來讓我們方便地使用它來實現進程間的通信。它的用法與其他兩個System V PIC機制,即信號量和共用記憶體相似。   1、msgget函數 該函數用來創建和訪問一個消息隊列。它的原型為: [cpp] view plain copy    print?
  1. int msgget(key_t, key, int msgflg);  
與其他的IPC機制一樣,程式必須提供一個鍵來命名某個特定的消息隊列。msgflg是一個許可權標誌,表示消息隊列的訪問許可權,它與文件的訪問許可權一樣。msgflg可以與IPC_CREAT做或操作,表示當key所命名的消息隊列不存在時創建一個消息隊列,如果key所命名的消息隊列存在時,IPC_CREAT標誌會被忽略,而只返回一個標識符。   它返回一個以key命名的消息隊列的標識符(非零整數),失敗時返回-1.   2、msgsnd函數 該函數用來把消息添加到消息隊列中。它的原型為: [cpp] view plain copy    print?
  1. int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);  
msgid是由msgget函數返回的消息隊列標識符。   msg_ptr是一個指向準備發送消息的指針,但是消息的數據結構卻有一定的要求,指針msg_ptr所指向的消息結構一定要是以一個長整型成員變數開始的結構體,接收函數將用這個成員來確定消息的類型。所以消息結構要定義成這樣:   [cpp] view plain copy    print?
  1. struct my_message{  
  2.     long int message_type;  
  3.     /* The data you wish to transfer*/  
  4. };  
msg_sz是msg_ptr指向的消息的長度,註意是消息的長度,而不是整個結構體的長度,也就是說msg_sz是不包括長整型消息類型成員變數的長度。   msgflg用於控制當前消息隊列滿或隊列消息到達系統範圍的限制時將要發生的事情。   如果調用成功,消息數據的一分副本將被放到消息隊列中,並返回0,失敗時返回-1.   3、msgrcv函數 該函數用來從一個消息隊列獲取消息,它的原型為 [cpp] view plain copy    print?
  1. int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);  
msgid, msg_ptr, msg_st的作用也函數msgsnd函數的一樣。   msgtype可以實現一種簡單的接收優先順序。如果msgtype為0,就獲取隊列中的第一個消息。如果它的值大於零,將獲取具有相同消息類型的第一個信息。如果它小於零,就獲取類型等於或小於msgtype的絕對值的第一個消息。   msgflg用於控制當隊列中沒有相應類型的消息可以接收時將發生的事情。   調用成功時,該函數返回放到接收緩存區中的位元組數,消息被覆制到由msg_ptr指向的用戶分配的緩存區中,然後刪除消息隊列中的對應消息。失敗時返回-1.   4、msgctl函數 該函數用來控制消息隊列,它與共用記憶體的shmctl函數相似,它的原型為: [cpp] view plain copy    print?
  1. int msgctl(int msgid, int command, struct msgid_ds *buf);  
command是將要採取的動作,它可以取3個值,     IPC_STAT:把msgid_ds結構中的數據設置為消息隊列的當前關聯值,即用消息隊列的當前關聯值覆蓋msgid_ds的值。     IPC_SET:如果進程有足夠的許可權,就把消息列隊的當前關聯值設置為msgid_ds結構中給出的值     IPC_RMID:刪除消息隊列   buf是指向msgid_ds結構的指針,它指向消息隊列模式和訪問許可權的結構。msgid_ds結構至少包括以下成員:   [cpp] view plain copy    print?
  1. struct msgid_ds  
  2. {  
  3.     uid_t shm_perm.uid;  
  4.     uid_t shm_perm.gid;  
  5.     mode_t shm_perm.mode;  
  6. };  
成功時返回0,失敗時返回-1.   三、使用消息隊列進行進程間通信 馬不停蹄,介紹完消息隊列的定義和可使用的介面之後,我們來看看它是怎麼讓進程進行通信的。由於可以讓不相關的進程進行行通信,所以我們在這裡將會編寫兩個程式,msgreceive和msgsned來表示接收和發送信息。根據正常的情況,我們允許兩個程式都可以創建消息,但只有接收者在接收完最後一個消息之後,它才把它刪除。   接收信息的程式源文件為msgreceive.c的源代碼為:   [cpp] view plain copy    print?
  1. #include <unistd.h>  
  2. #include <stdlib.h>  
  3. #include <stdio.h>  
  4. #include <string.h>  
  5. #include <errno.h>  
  6. #include <sys/msg.h>  
  7.   
  8. struct msg_st  
  9. {  
  10.     long int msg_type;  
  11.     char text[BUFSIZ];  
  12. };  
  13.   
  14. int main()  
  15. {  
  16.     int running = 1;  
  17.     int msgid = -1;  
  18.     struct msg_st data;  
  19.     long int msgtype = 0; //註意1  
  20.   
  21.     //建立消息隊列  
  22.     msgid = msgget((key_t)1234, 0666 | IPC_CREAT);  
  23.     if(msgid == -1)  
  24.     {  
  25.         fprintf(stderr, "msgget failed with error: %d\n", errno);  
  26.         exit(EXIT_FAILURE);  
  27.     }  
  28.     //從隊列中獲取消息,直到遇到end消息為止  
  29.     while(running)  
  30.     {  
  31.         if(msgrcv(msgid, (void*)&data, BUFSIZ, msgtype, 0) == -1)  
  32.         {  
  33.             fprintf(stderr, "msgrcv failed with errno: %d\n", errno);  
  34.             exit(EXIT_FAILURE);  
  35.         }  
  36.         printf("You wrote: %s\n",data.text);  
  37.         //遇到end結束  
  38.         if(strncmp(data.text, "end", 3) == 0)  
  39.             running = 0;  
  40.     }  
  41.     //刪除消息隊列  
  42.     if(msgctl(msgid, IPC_RMID, 0) == -1)  
  43.     {  
  44.         fprintf(stderr, "msgctl(IPC_RMID) failed\n");  
  45.         exit(EXIT_FAILURE);  
  46.     }  
  47.     exit(EXIT_SUCCESS);  
  48. }  
發送信息的程式的源文件msgsend.c的源代碼為:   [cpp] view plain copy    print?
  1. #include <unistd.h>  
  2. #include <stdlib.h>  
  3. #include <stdio.h>  
  4. #include <string.h>  
  5. #include <sys/msg.h>  
  6. #include <errno.h>  
  7.   
  8. #define MAX_TEXT 512  
  9. struct msg_st  
  10. {  
  11.     long int msg_type;  
  12.     char text[MAX_TEXT];  
  13. };  
  14.   
  15. int main()  
  16. {  
  17.     int running = 1;  
  18.     struct msg_st data;  
  19.     char buffer[BUFSIZ];  
  20.     int msgid = -1;  
  21.   
  22.     //建立消息隊列  
  23.     msgid = msgget((key_t)1234, 0666 | IPC_CREAT);  
  24.     if(msgid == -1)  
  25.     {  
  26.         fprintf(stderr, "msgget failed with error: %d\n", errno);  
  27.         exit(EXIT_FAILURE);  
  28.     }  
  29.   
  30.     //向消息隊列中寫消息,直到寫入end  
  31.     while(running)  
  32.     {  
  33.         //輸入數據  
  34.         printf("Enter some text: ");  
  35.         fgets(buffer, BUFSIZ, stdin);  
  36.         data.msg_type = 1;    //註意2  
  37.         strcpy(data.text, buffer);  
  38.         //向隊列發送數據  
  39.         if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1)  
  40.         {  
  41.             fprintf(stderr, "msgsnd failed\n");  
  42.             exit(EXIT_FAILURE);  
  43.         }  
  44.         //輸入end結束輸入  
  45.         if(strncmp(buffer, "end", 3) == 0)  
  46.             running = 0;  
  47.         sleep(1);  
  48.     }  
  49.     exit(EXIT_SUCCESS);  
  50. }  
運行結果如下:     四、例子分析——消息類型   這裡主要說明一下消息類型是怎麼一回事,註意msgreceive.c文件main函數中定義的變數msgtype(註釋為註意1),它作為msgrcv函數的接收信息類型參數的值,其值為0,表示獲取隊列中第一個可用的消息。再來看看msgsend.c文件中while迴圈中的語句data.msg_type = 1(註釋為註意2),它用來設置發送的信息的信息類型,即其發送的信息的類型為1。所以程式msgreceive能夠接收到程式msgsend發送的信息。   如果把註意1,即msgreceive.c文件main函數中的語句由long int msgtype = 0;改變為long int msgtype = 2;會發生什麼情況,msgreceive將不能接收到程式msgsend發送的信息。因為在調用msgrcv函數時,如果msgtype(第四個參數)大於零,則將只獲取具有相同消息類型的第一個消息,修改後獲取的消息類型為2,而msgsend發送的消息類型為1,所以不能被msgreceive程式接收。重新編譯msgreceive.c文件並再次執行,其結果如下:     我們可以看到,msgreceive並沒有接收到信息和輸出,而且當msgsend輸入end結束後,msgreceive也沒有結束,通過jobs命令我們可以看到它還在後臺運行著。   五、消息隊列與命名管道的比較   消息隊列跟命名管道有不少的相同之處,通過與命名管道一樣,消息隊列進行通信的進程可以是不相關的進程,同時它們都是通過發送和接收的方式來傳遞數據的。在命名管道中,發送數據用write,接收數據用read,則在消息隊列中,發送數據用msgsnd,接收數據用msgrcv。而且它們對每個數據都有一個最大長度的限制。   與命名管道相比,消息隊列的優勢在於,1、消息隊列也可以獨立於發送和接收進程而存在,從而消除了在同步命名管道的打開和關閉時可能產生的困難。2、同時通過發送消息還可以避免命名管道的同步和阻塞問題,不需要由進程自己來提供同步方法。3、接收程式可以通過消息類型有選擇地接收數據,而不是像命名管道中那樣,只能預設地接收。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.什麼是資料庫? 俗稱數據的倉庫,方便管理數據的軟體(或程式) 2.MySQL入門 1.官網下載 2.安裝MySql 直接雙擊安裝即可,但註意安裝的目錄不可出現中文。 2.1驗證安裝是否成功 打開命令行-->輸入 "mysql -u root -p" 回車,輸入密碼-->回車 出現以下內容,即為成 ...
  • 介紹 物理故障、操作系統故障或 SQL Server 故障都可能導致兩個可用性副本之間的會話失敗。 可用性副本不會定期檢查 Sqlservr.exe 所依賴的組件來驗證這些組件是在正常運行還是已出現故障。 但對於某些類型的故障,受影響的組件將向 Sqlservr.exe 報告錯誤。 由另一個組件報告 ...
  • MariaDB資料庫管理系統是MySQL的一個分支,主要由開源社區在維護,採用GPL授權許可 MariaDB的目的是完全相容MySQL,包括API和命令行,使之能輕鬆成為MySQL的代替品。在存儲引擎方面,使用XtraDB(英語:XtraDB)來代替MySQL的InnoDB。 MariaDB由MyS ...
  • MySQL中lock tables和unlock tables淺析 在MySQL中提供了鎖定表(lock tables)和解鎖表(unlock tables)的語法功能,ORACLE與SQL Server資料庫當中沒有這種語法。相信剛接觸MySQL的人,都想詳細、深入的瞭解一下這個功能.下麵就儘量全... ...
  • 本篇主要介紹MongoDB可視化操作以及shell使用及命令。 MongoVUE安裝和簡單使用 使用mongo.exe 管理資料庫雖然可行,功能也挺強大,但每次都要敲命令,即繁瑣枯燥而且效率低下。MongoDb在Windows下的可視化操作的管理工具非常多,筆者從中找了幾款使用了一翻,最後挑了一款M ...
  • 1、基本構成 (1)需要查詢的表(單表,多表) (2)需要查詢的信息(欄位信息,過濾處理) (3)查詢條件(欄位關聯,欄位值範圍,記錄截取設置,排序方式,分組方式,去重,or ,and) 2、實例展示(以user表為例) 2.1查詢單表(user) (1)查詢單表所有欄位 select * from ...
  • 轉自:http://cheneyph.iteye.com/blog/824746 系統 資源 磁碟和分區 網路 進程 用戶 服務 程式 ...
  • 如有錯誤希望各位大佬批評指正,郵件請發:[email protected] ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...