一.進程間通信的實現
進程間通信 (Inter-process communication, IPC):
運行在不同進程中的若干線程間的數據交換
1 常用的進程通信模式
1.1 共享內存
兩個進程可以直接共享訪問同一塊內存區域,減少了數據的復制操作,速度優勢比較明顯。
共享內存
一般步驟如下:
- 創建內存共享區,進程1通過系統提供的API從內存中申請一塊共享區域,例如Linux中使用shmget進行實現,生成的共享內存塊與某個特定key值綁定。
- 進程1通過shmat函數將共享內存映射到進程1的空間中。
- 訪問內存共享區,進程2同樣調用shmget函數,并將相同的key值傳入即可。然后進程2執行shmat,將內存映射到它的空間中。
- 進程間通信,共享內存在各個進程間實現映射之后,便可以作為信息交換的區域。進程間需要自己協商同步機制,防止信息錯亂。
- 撤銷內存映射區,進程間通信完成后,各進程都要撤銷之前的映射操作,Linux中通過shmdt函數實現。
- 刪除內存共享區,以便回收內存。Linxu中通過shctl實現。
1.2 管道(pipe)
管道也是操作系統中常用的進程間通信方式,適用于所有的POSIX系統以及Windows系列產品
Pipe很形象地形容了通信雙方的行為:進程A與進程B:
- 分別在管道的兩邊,進行數據傳輸通信
- 管道是單向的,如果一個進程既要“讀”又要“寫” 的話,則需要建立兩根管道。
- 一根管道的兩端分別是“讀取端 read end”和“寫入端 write end”;進程1從寫入端寫進數據,進程2從讀取端讀取到數據。
- 管道有容量限制,pipe滿時,寫操作將阻塞,反之,讀操作也會阻塞。
Linux pipe示例
上圖是父進程向管道中輸入一個“H”字符,子進程讀取后輸出
- pipe接口的函數原型:
int pipe (int pipefd[2], int flags); //第一個參數代表成功打開后管道的兩端
- 此例中的管道文件描述符
pipe_fd
,因為是父子進程的關系可以共享,如果兩個進程中沒有任何關系,則無法使用這種方式進行共享(Named Pipe (也被成為FIFO) 作為pipe的擴展可以解決這種問題,它改變了上例中“匿名”的方式;由于它的生命周期不再隨著進程結束而結束,因此我們在不使用的時候要主動刪除)
1.3 Unix Domain Socket
UDS 是專門針對單機內進程間通信提出的,也被稱為IPC Socket。
與Network Socket的區別:
- Network Socket: 基于TCP/IP 協議,需要分包,重組等一系列操作
-
UDS: 本機內的“安全可靠操作”,不依賴這些協議
UDS通信流程
1.4 RPC (Remote Procedure Calls)
RPC通信通常運行于兩臺不同的及其中。在RPC機制中,客戶端和服務端的通信傳輸過程用戶不需要關心,這種“透明性”可以大大降低研發難度。
RPC通信的過程:
- 客戶端進程調用Stub接口
- Stub根據操作系統要求進行打包,并執行相應的系統調用
- 由內核(RPC Runtime Library)來完成與服務端的交互
- 服務端Stub解包并調用與數據包匹配的進程
- 服務端進程執行操作
RPC通信圖釋