主頁 > 作業系統 > 【行程間通信】常用方式匯總

【行程間通信】常用方式匯總

2022-10-20 06:08:14 作業系統

【行程間通信】常用方式匯總

隨著我們的行程越來越多,難免不同行程之間要互相傳輸一些資料,那么這個時候該怎么辦呢?

下面主要簡單了解一下,行程間通信(InterProcess Communication,IPC)的幾種實作方式!

 

1、管道模型

管道模型與軟體生命周期模型——瀑布模型(Waterfall Model)很相似,

所謂的瀑布模型,其實就是將整個軟體開發程序分成多個階段,往往是上一個階段完全做完,才將輸出結果交給下一個階段,

image-20220922134815245

還記得咱們最初學 Linux 命令的時候,有下面這樣一行命令:

ps -ef | grep 關鍵字 | awk '{print $2}' | xargs kill -9

這里面的豎線“|”就是一個管道,它會將前一個命令的輸出,作為后一個命令的輸入,

從管道的這個名稱可以看出來,管道是一種單向傳輸資料的機制,它其實是一段快取,里面的資料只能從一端寫入,從另一端讀出,如果想互相通信,我們需要創建兩個管道才行,

管道又可以分為匿名管道和命名管道!

 

1.1 匿名管道

如上命令:

ps -ef | grep 關鍵字 | awk '{print $2}' | xargs kill -9

匿名管道:用"|” 表示的管道,意思就是這個型別的管道沒有名字,用完了就銷毀了,豎線代表的管道隨著命令的執行自動創建、自動銷毀,用戶甚至都不知道自己在用管道這種技術,就已經解決了問題,

 

1.2 命名管道

命名管道,這個型別的管道需要通過 mkfifo 命令顯式地創建,

mkfifo donge		#建立一個管道

donge就是這個管道的名稱,管道以檔案的形式存在,這也符合 Linux 里面一切皆檔案的原則,

 

下面我們看一下檔案型別

ls -l
prw-rw-r-- 1 dong dong     0 Sep 28 17:09 donge

可以看到,這個檔案的型別是 p,就是 pipe 的意思,

 

往管道中寫入資料

echo "hello world" > donge

這個時候,管道里面的內容沒有被讀出,這個命令就是停在這里的,即行程被堵塞,

這說明當一個專案組要把它的輸出交接給另一個專案組做輸入,當沒有交接完畢的時候,前一個專案組是不能撒手不管的,

重新打開一個終端,讀出管道資料

cat < hello 
hello world

一方面,我們能夠看到,管道里面的內容被讀取出來,列印到了終端上;

另一方面,echo 那個命令正常退出了,也即交接完畢,前一個專案組就完成了使命,可以解散了,

 

管道通信,我們可以看出,瀑布模型的開發流程效率比較低下,因為團隊之間無法頻繁地溝通,而且,管道的使用模式,也不適合行程間頻繁的交換資料

 

2、訊息佇列

image-20220922135603302

訊息佇列可以理解為發郵件,每一封郵件都視為一個獨立的資料單元,也就是訊息體,每個訊息體都是固定大小的存盤塊,在位元組流上不連續

這個訊息結構的定義我寫在下面了,這里面的型別 type 和正文 text 沒有強制規定,只要訊息的發送方和接收方約定好即可,

struct msg_buffer {
    long mtype;
    char mtext[1024];
};

 

2.1 創建訊息佇列

訊息佇列的創建,需要用到msgget函式

int msgget(key_t key, int msgflg);
  • key:該引數是訊息佇列的唯一標識,由ftok生成,

  • msgflg:取值有以下幾個選擇:IPC_CREATIPC_EXCL ,這兩個引數詳細的作用可以man msgflg看詳細介紹,

  • 回傳值:回傳一個近乎唯一的Message queue id

 

那么,key是如何由ftok生成的呢?

我們可以指定一個檔案,呼叫ftok ,它會根據這個檔案的 inode,生成一個近乎唯一的 key

key_t ftok(const char *pathname, int proj_id);
  • pathname:檔案資訊,必須指定在一個存在的,可訪問的檔案
  • proj_id8bit的資料,0-255隨意設定

這樣就可以獲得一個近乎唯一的key了!

 

只要在這個訊息佇列的生命周期內,這個檔案不要被洗掉就可以了,只要不洗掉,無論什么時刻,再呼叫 ftok,也會得到同樣的 key,

 

綜上,創建一個訊息佇列只需兩步:

①:ftok生成一個key

②:msgget生成一個訊息佇列的ID

如下:

#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
 
 
int main() {
  int messagequeueid;
  key_t key;
 
 
  if((key = ftok("/root/messagequeue/messagequeuekey", 1)) < 0)
  {
      perror("ftok error");
      exit(1);
  }
 
 
  printf("Message Queue key: %d.\n", key);
 
 
  if ((messagequeueid = msgget(key, IPC_CREAT|0777)) == -1)
  {
      perror("msgget error");
      exit(1);
  }
 
 
  printf("Message queue id: %d.\n", messagequeueid);
}

ftok要指定一個存在的檔案,所以我們在執行之前,需要創建該檔案,

 

查看訊息佇列

System V IPC 體系有一個統一的命令列工具:ipcmkipcsipcrm 用于創建、查看和洗掉 IPC 物件,

查看創建的IPC物件:ipcs -q

dong@ubuntu:~//Interprocess_Communication$ ipcs 

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x01110005 0          dong       777        0            0           

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      

------ Semaphore Arrays --------
key        semid      owner      perms      nsems

 

2.2 發送訊息

訊息佇列發送訊息,主要呼叫msgsnd 函式

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
  • msqid:該引數是msgget所得到的message queueid
  • msgp:訊息結構體
struct msg_buffer {
    long mtype;
    char mtext[1024];
};
  • msgsz:表示訊息結構體中,mtext最大長度
  • msgflg:一位掩碼,可取值有:IPC_NOWAITMSG_COPYMSG_EXCEPTMSG_NOERROR,取值說明可見man msgsnd

 

2.3 接收訊息

訊息佇列接收訊息,主要呼叫msgrcv 函式

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
                      int msgflg);
  • msqid:該引數是msgget所得到的message queueid
  • msgp:訊息結構體
  • msgsz:可接收資料最大長度
  • msgflg:一位掩碼,可取值有:IPC_NOWAITMSG_COPYMSG_EXCEPTMSG_NOERROR,取值說明可見man msgsnd

 

有了訊息這種模型,兩個行程之間的通信就像咱們平時發郵件一樣,你來一封,我回一封,可以頻繁溝通了,

 

3、共享記憶體

image-20220924172026172

怎么理解共享記憶體呢?

我們知道每個行程都有自己獨立的虛擬記憶體空間不同的行程的虛擬記憶體空間映射到不同的物理記憶體中去,這個行程訪問 A 地址和另一個行程訪問 A 地址,其實訪問的是不同的物理記憶體地址,對于資料的增刪查改互不影響,

 

但是,咱們是不是可以變通一下,拿出一塊虛擬地址空間來,映射到相同的物理記憶體中,這樣這個行程寫入的東西,另外一個行程馬上就能看到了,都不需要拷貝來拷貝去,傳來傳去,

 

相比于訊息佇列,共享記憶體的優勢在哪里呢?

  • 大資料傳輸:如果批量的大資料進行傳輸,使用郵件的方式,來去發送不及時,并且大小也有限制
  • 實時性:用共享記憶體,其可以大大節省通信時間

 

3.1 創建共享記憶體

我們可以創建一個共享記憶體,呼叫 shmget

int shmget(key_t key, size_t size, int shmflg);
  • key:和 msgget 里面的 key 一樣,都是唯一定位一個共享記憶體的物件
  • size:共享記憶體的大小
  • shmflg:其值可以取:IPC_CREATIPC_EXCLSHM_HUGETLBSHM_HUGE_2MB

回傳值:共享記憶體的唯一ID

 

創建完畢之后,我們可以通過 ipcs 命令查看這個共享記憶體,

#ipcs --shmems
 
------ Shared Memory Segments ------ --------
key        shmid    owner perms    bytes nattch status
0x00000000 19398656 marc  600    1048576 2      dest

 

3.2 訪問共享記憶體

接下來,如果一個行程想要訪問這一段共享記憶體,需要將這個記憶體加載到自己的虛擬地址空間的某個位置,通過 shmat 函式,就是 attach 的意思,

void *shmat(int shmid, const void *shmaddr, int shmflg);
  • shmid:標識一個共享記憶體段的唯一ID
  • shmaddr:就是要指定 attach 到這個地方,但是這個地址的設定難度比較大,除非對于記憶體布局非常熟悉,否則可能會 attach到一個非法地址,所以,通常的做法是將 shmaddr設為 NULL,讓內核選一個合適的地址,
  • shmflg:一位掩碼,可取值:SHM_EXECSHM_RDONLYSHM_REMAP

回傳值:為所連接的實際地址

 

3.3 關閉共享記憶體

如果共享記憶體使用完畢,可以通過 shmdt 解除系結,然后通過 shmctl,將 cmd 設定為 IPC_RMID,從而洗掉這個共享記憶體物件,

int shmdt(void *addr); 
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

shmdt的引數addr:為shmat的回傳值,表示卸載一片共享記憶體

shmctl的引數:

  • shm_idshmget的回傳值,為共享記憶體的唯一ID
  • cmd:取值有:IPC_STATIPC_RMID等,見:man shmctl
  • buf:共享記憶體管理結構體,

 

3.4 信號量

這里你是不是有一個疑問,如果兩個行程 attach 同一個共享記憶體,大家都往里面寫東西,很有可能就沖突了,例如兩個行程都同時寫一個地址,那先寫的那個行程會發現內容被別人覆寫了,

 

所以,這里就需要一種保護機制,使得同一個共享的資源,同時只能被一個行程訪問,在 System V IPC 行程間通信機制體系中,早就想好了應對辦法,就是信號量(Semaphore,因此,信號量和共享記憶體往往要配合使用,

 

信號量和共享記憶體都比較復雜,兩者還要結合起來用,就更加復雜,它們內核的機制就更加復雜,這一節我們先不講,

 

4、信號

上面講的行程間通信的方式,都是常規狀態下的作業模式,對應到咱們平時的作業交接,收發郵件、聯合開發等,其實還有一種例外情況下的作業模式

例如出現線上系統故障,這個時候,什么流程都來不及了,不可能發郵件,也來不及開會,所有的架構師、開發、運維都要被通知緊急出動,所以,7 乘 24 小時不間斷執行的系統都需要有告警系統,一旦出事情,就要通知到人,哪怕是半夜,也要電話叫起來,處理故障,

信號可以在任何時候發送給某一行程,行程需要為這個信號配置信號處理函式,

Linux所支持的例外信號如下:

 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

當某個信號發生的時候,就默認執行這個函式就可以了,這就相當于咱們運維一個系統應急手冊,當遇到什么情況,做什么事情,都事先準備好,出了事情照著做就可以了,

有點類似于例外中斷……

OK,這一篇,我們整體講解了一下行程間通信的幾種方式,現在我們來回顧一下:

  • 類似瀑布開發模型的管道
  • 類似郵件模式的訊息佇列
  • 類似會議室聯合開發的共享記憶體加信號量
  • 類似應急預案的信號

Peek 2022-09-25 22-04

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/518447.html

標籤:Linux

上一篇:nginx組態檔,rewrite,if

下一篇:Ansible簡介

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • CA和證書

    1、在 CentOS7 中使用 gpg 創建 RSA 非對稱密鑰對 gpg --gen-key #Centos上生成公鑰/密鑰對(存放在家目錄.gnupg/) 2、將 CentOS7 匯出的公鑰,拷貝到 CentOS8 中,在 CentOS8 中使用 CentOS7 的公鑰加密一個檔案 gpg -a ......

    uj5u.com 2020-09-10 00:09:53 more
  • Kubernetes K8S之資源控制器Job和CronJob詳解

    Kubernetes的資源控制器Job和CronJob詳解與示例 ......

    uj5u.com 2020-09-10 00:10:45 more
  • VMware下安裝CentOS

    VMware下安裝CentOS 一、軟硬體準備 1 Centos鏡像準備 1.1 CentOS鏡像下載地址 下載地址 1.2 CentOS鏡像下載程序 點擊下載地址進入如下圖的網站,選擇需要下載的版本,這里選擇的是Centos8,點擊如圖所示。 決定選擇Centos8后,選擇想要的鏡像源進行下載,此 ......

    uj5u.com 2020-09-10 00:12:10 more
  • 如何使用Grep命令查找多個字串

    如何使用Grep 命令查找多個字串 大家好,我是良許! 今天向大家介紹一個非常有用的技巧,那就是使用 grep 命令查找多個字串。 簡單介紹一下,grep 命令可以理解為是一個功能強大的命令列工具,可以用它在一個或多個輸入檔案中搜索與正則運算式相匹配的文本,然后再將每個匹配的文本用標準輸出的格式 ......

    uj5u.com 2020-09-10 00:12:28 more
  • git配置http代理

    git配置http代理 經常遇到克隆 github 慢的問題,這里記錄一下幾種配置 git 代理的方法,解決 clone github 過慢。 目錄 git配置代理 git單獨配置github代理 git配置全域代理 配置終端環境變數 git配置代理 主要使用 git config 命令 git單獨 ......

    uj5u.com 2020-09-10 00:12:33 more
  • Linux npm install 裝包時提示Error EACCES permission denied解

    npm install 裝包時提示Error EACCES permission denied解決辦法 ......

    uj5u.com 2020-09-10 00:12:53 more
  • Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包

    Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包。 18 (flaskApi) [root@67 flaskDemo]# yum -y install nginx 19 已加載插件:fastestmirror, langpacks 20 Loading ......

    uj5u.com 2020-09-10 00:13:13 more
  • Linux查看服務器暴力破解ssh IP

    在公網的服務器上經常遇到別人爆破你服務器的22埠,用來挖礦或者干其他嘿嘿嘿的事情~ 這種情況下正確的做法是: 修改默認ssh的22埠 使用設定密鑰登錄或者白名單ip登錄 建議服務器密碼為復雜密碼 創建普通用戶登錄服務器(root權限過大) 建立堡壘機,實作統一管理服務器 統計爆破IP [root ......

    uj5u.com 2020-09-10 00:13:17 more
  • CentOS 7系統常見快捷鍵操作方式

    Linux系統中一些常見的快捷方式,可有效提高操作效率,在某些時刻也能避免操作失誤帶來的問題。 ......

    uj5u.com 2020-09-10 00:13:31 more
  • CentOS 7作業系統目錄結構介紹

    作業系統存在著大量的資料檔案資訊,相應檔案資訊會存在于系統相應目錄中,為了更好的管理資料資訊,會將系統進行一些目錄規劃,不同目錄存放不同的資源。 ......

    uj5u.com 2020-09-10 00:13:35 more
最新发布
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:43:21 more
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:42:36 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:26:53 more
  • 設定Windows主機的瀏覽器為wls2的默認瀏覽器

    這里以Chrome為例。 1. 準備作業 wsl是可以使用Windows主機上安裝的exe程式,出于安全考慮,默認情況下改功能是無法使用。要使用的話,終端需要以管理員權限啟動。 我這里以Windows Terminal為例,介紹如何默認使用管理員權限打開終端,具體操作如下圖所示: 2. 操作 wsl ......

    uj5u.com 2023-04-19 09:25:49 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:19:04 more
  • Linux學習筆記

    IP地址和主機名 IP地址 ifconfig可以用來查詢本機的IP地址,如果不能使用,可以通過install net-tools安裝。 Centos系統下ens33表示主網卡;inet后表示IP地址;lo表示本地回環網卡; 127.0.0.1表示代指本機;0.0.0.0可以用于代指本機,同時在放行設 ......

    uj5u.com 2023-04-18 06:52:01 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:50 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:01 more
  • 你是不是暴露了?

    作者:袁首京 原創文章,轉載時請保留此宣告,并給出原文連接。 如果您是計算機相關從業人員,那么應該經歷不止一次網路安全專項檢查了,你肯定是收到過資訊系統技術檢測報告,要求你加強風險監測,確保你提供的系統服務堅實可靠了。 沒檢測到問題還好,檢測到問題的話,有些處理起來還是挺麻煩的,尤其是線上正在運行的 ......

    uj5u.com 2023-04-05 16:52:56 more
  • 細節拉滿,80 張圖帶你一步一步推演 slab 記憶體池的設計與實作

    1. 前文回顧 在之前的幾篇記憶體管理系列文章中,筆者帶大家從宏觀角度完整地梳理了一遍 Linux 記憶體分配的整個鏈路,本文的主題依然是記憶體分配,這一次我們會從微觀的角度來探秘一下 Linux 內核中用于零散小記憶體塊分配的記憶體池 —— slab 分配器。 在本小節中,筆者還是按照以往的風格先帶大家簡單 ......

    uj5u.com 2023-04-05 16:44:11 more