什么是管道通信?Linux下匿名管道和命名管道的區(qū)別與用法
介紹
進(jìn)程間通信目的
首先我們要了解進(jìn)程間通信的目的,一共有4點(diǎn)
1:數(shù)據(jù)傳輸:一個(gè)進(jìn)程需要將它的數(shù)據(jù)傳輸給另一個(gè)進(jìn)程
2:資源共享:多個(gè)進(jìn)程之間共享同樣的資源
2:通知事件:一個(gè)進(jìn)程給另一個(gè)進(jìn)程發(fā)送信息,通知發(fā)生了某種事件
4:進(jìn)程控制:某些進(jìn)程希望完全控制另一個(gè)進(jìn)程的執(zhí)行,此時(shí)進(jìn)程希望另一個(gè)進(jìn)程能進(jìn)行攔截另一個(gè)進(jìn)程的一場,并能夠及時(shí)知道它的狀態(tài)改變
進(jìn)程間通信發(fā)展
管道,SystemV進(jìn)程間通信,POSIX進(jìn)程間通信
其中這三個(gè)都有各自的分支
- 管道:匿名管道pipe,命名管道
- SystemV IPC:System V 消息隊(duì)列/共享內(nèi)存/信號(hào)量
- POSIX IPC:消息隊(duì)列,共享內(nèi)存,信號(hào)量,互斥量,條件變量,讀寫鎖
管道
什么是管道:管道是UNIX系統(tǒng)最古老的進(jìn)程間通信方式
一個(gè)進(jìn)程鏈接另一個(gè)進(jìn)程的另一個(gè)數(shù)據(jù)流成為一個(gè)管道
匿名管道
這里是示例代碼
#include<unistd.h> //功能是創(chuàng)建無名管道 int pipe(int fd[2]); //參數(shù)解釋:fd為文件描述符數(shù)組,fd[0]是讀端,fd[1]為寫端
用fork來共享管道原理

站在文件描述符角度-深度理解管道

站在內(nèi)核角度

測試管道讀寫代碼示例
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#define ERR_EXIT(m)
do {
perror(m);
exit(EXIT_FAILURE);
} while (0)
int main(int argc, char* argv[])
{
int pipefd[2];
if (pipe(pipefd) == -1)
ERR_EXIT("pipe error");
pid_t pid;
pid = fork();
if (pid == -1)
{
ERR_EXIT("fork error");
}
if (pid == 0)
{
close(pipefd[0]);
write(pipefd[1], "hello", 9);
close(pipefd[1]);
exit(EXIT_SUCCESS);
}
close(pipefd[1]);
char buf[10] = { 0 };
read(pipefd[0], buf, 10);
printf("buf=%s\n", buf);
return 0;
}
管道讀寫規(guī)則
當(dāng)沒有數(shù)據(jù)可讀時(shí)
- O_NONBLOCK disable:read 調(diào)用阻塞,進(jìn)程暫停執(zhí)行,一直等到數(shù)據(jù)來到為止
- O_NONBLOCK enable :read調(diào)用返回-1,errno值為EAGAIN
當(dāng)管道滿的時(shí)候
- O_NONBLOCK disable:write調(diào)用阻塞,直到有進(jìn)程讀走數(shù)據(jù)
- O_NONBLOCK enable:調(diào)用返回-1,errno值為EAGAIN
- 如果所有管道讀寫對(duì)應(yīng)文件描述符被關(guān)閉,errno為EAGAIN
- 如果所有管道讀端量不大于PIPE_BUF時(shí),linux將保證寫入的原子性
- 當(dāng)要寫?的數(shù)據(jù)量?于PIPE_BUF時(shí),linux將不再保證寫?的原?性。
管道特點(diǎn)
只能用于具有共同祖先的進(jìn)程之間進(jìn)行通信,通常一個(gè)管道由一個(gè)進(jìn)程創(chuàng)建,然后進(jìn)程調(diào)用fork,此后父子進(jìn)程之間可用該管道
管道提供流式服務(wù)
- 一般而言,進(jìn)程退出管道釋放
- 所以管道的生命周期隨進(jìn)程變化而變化
- 管道是半雙工的,數(shù)據(jù)只能向一個(gè)方向流動(dòng),需要雙方通信時(shí),需要建立兩個(gè)管道
3-8驗(yàn)證管道通信的4種情況
- • 讀正常&&寫滿
- • 寫正常&&讀空
- • 寫關(guān)閉&&讀正常
- • 讀關(guān)閉&&寫正常
命名管道
管道應(yīng)用的一個(gè)限制就是只能在具有共同祖先的進(jìn)程間通信
如果我們?cè)诓幌嚓P(guān)的進(jìn)程間進(jìn)行通信,可以用FIFO文件進(jìn)行此工作,它通常被命名為管道
命名管道是一種特殊類型文件
創(chuàng)建命名管道
$ mkfifo filename
匿名管道和命名管道的區(qū)別
- 匿名管道是pipe函數(shù)創(chuàng)建并打開
- 命名管道由mkfifo函數(shù)創(chuàng)建,打開用open
- fifo和pipe之間唯一的區(qū)別就是他們創(chuàng)建和打開的方式不同,一旦這些工作完成之后,他們具有相同的語義
命名管道的打開規(guī)則
打開操作/未讀/打開fifo
- O_NONBLOCKdisable:阻塞直到有相應(yīng)進(jìn)程為寫?打開該FIF
- O_NONBLOCKenable:?刻返回成功
如果當(dāng)前打開操作是為寫?打開FIFO時(shí)
- O_NONBLOCK disable:阻塞直到有相應(yīng)進(jìn)程為讀?打開該FIFO
- O_NONBLOCK enable:?刻返回失敗,錯(cuò)誤碼為ENXIO
System V 共享內(nèi)存
共享內(nèi)存是最快的IPC形式,一旦這樣的內(nèi)存映射搭配共享它的進(jìn)程的地址空間,這些進(jìn)程間數(shù)據(jù)傳遞不再涉及到內(nèi)核,換句話說是進(jìn)程不在通過執(zhí)行進(jìn)入內(nèi)核的操作系統(tǒng)調(diào)用來傳遞彼此的數(shù)據(jù)
5-3 共享內(nèi)存相關(guān)函數(shù)
一、shmget ():創(chuàng)建 / 獲取共享內(nèi)存
功能
創(chuàng)建一塊新共享內(nèi)存段,或獲取已存在的共享內(nèi)存段標(biāo)識(shí)。
函數(shù)原型
int shmget(key_t key, size_t size, int shmflg);
參數(shù)說明
- key:共享內(nèi)存鍵值,標(biāo)識(shí)共享內(nèi)存段的唯一名字,不同進(jìn)程通過相同 key 訪問同一塊共享內(nèi)存。
- size:共享內(nèi)存段字節(jié)大小,創(chuàng)建時(shí)指定,獲取已有段時(shí)填 0 即可。
- shmflg:權(quán)限 + 控制標(biāo)志,用法同文件 open 的 mode 權(quán)限,常用組合:
- IPC_CREAT:不存在則創(chuàng)建;已存在則直接獲取該段。
- IPC_CREAT | IPC_EXCL:不存在則創(chuàng)建;已存在函數(shù)報(bào)錯(cuò)返回 - 1,保證新建。
返回值
- 成功:返回非負(fù)整數(shù) shmid(共享內(nèi)存操作標(biāo)識(shí))
- 失?。悍祷?-1
二、shmat ():掛載共享內(nèi)存到進(jìn)程虛擬地址空間
功能
將指定共享內(nèi)存段映射、連接到當(dāng)前進(jìn)程的地址空間,掛載后進(jìn)程可直接讀寫這塊內(nèi)存。
函數(shù)原型
void *shmat(int shmid, const void *shmaddr, int shmflg);
參數(shù)說明
- shmid:shmget 返回的共享內(nèi)存標(biāo)識(shí)符。
- shmaddr:手動(dòng)指定掛載地址
- 傳 NULL:由操作系統(tǒng)內(nèi)核自動(dòng)分配合適地址(最常用);
- 非 NULL:用戶手動(dòng)指定掛載起始地址。
- shmflg:掛載屬性標(biāo)志,兩個(gè)常用取值:
- SHM_RDONLY:只讀掛載,進(jìn)程只能讀共享內(nèi)存,不可寫;
- SHM_RND:地址對(duì)齊標(biāo)志。
地址對(duì)齊規(guī)則說明
- shmaddr == NULL:內(nèi)核自動(dòng)分配地址,無需處理對(duì)齊;
- shmaddr != NULL 且無 SHM_RND:直接使用 shmaddr 作為掛載地址;
- shmaddr != NULL 且?guī)?SHM_RND:地址向下對(duì)齊到 SHMLBA 整數(shù)倍,計(jì)算公式:
實(shí)際掛載地址 = shmaddr - (shmaddr % SHMLBA)
返回值
- 成功:返回共享內(nèi)存段首地址指針;
- 失?。悍祷?(void *)-1
三、shmdt ():卸載共享內(nèi)存(脫離映射)
功能
斷開當(dāng)前進(jìn)程與共享內(nèi)存段的地址映射,進(jìn)程無法再訪問該共享內(nèi)存。
注意:僅脫離進(jìn)程映射,不會(huì)刪除操作系統(tǒng)中的共享內(nèi)存實(shí)體。
函數(shù)原型
int shmdt(const void *shmaddr);
參數(shù)說明
shmaddr:shmat 成功返回的共享內(nèi)存首地址指針。
返回值
- 成功:返回 0
- 失?。悍祷?-1
四、shmctl ():共享內(nèi)存控制(刪除 / 修改屬性 / 獲取狀態(tài))
功能
對(duì)共享內(nèi)存執(zhí)行控制操作:獲取狀態(tài)、修改權(quán)限、銷毀共享內(nèi)存段。
函數(shù)原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
參數(shù)說明
- shmid:shmget 返回的共享內(nèi)存標(biāo)識(shí);
- cmd:控制動(dòng)作指令(三種核心取值);
- buf:struct shmid_ds 結(jié)構(gòu)體指針,存儲(chǔ)共享內(nèi)存權(quán)限、狀態(tài)信息。
返回值
- 成功:返回 0
- 失敗:返回 -1
system V 消息隊(duì)列
消息隊(duì)列提供一個(gè)從一個(gè)進(jìn)程向另外一個(gè)進(jìn)程發(fā)送一塊數(shù)據(jù)的方法
每個(gè)數(shù)據(jù)塊都被認(rèn)為是有一個(gè)類型,接收者進(jìn)程接收的數(shù)據(jù)塊可以有不用的類型值
特性方面
IPC資源必須刪除,否則不會(huì)自動(dòng)刪除,除非自啟,所以System V ipc資源的生命周期隨內(nèi)核變化而變化
system V 信號(hào)量
多個(gè)執(zhí)行流程,能看到的同一份訪問資源,共享資源
被保護(hù)起來的共享資源:臨界資源
保護(hù)的方式常見為互斥和同步
任何時(shí)刻只允許一個(gè)執(zhí)行流訪問資源,叫做互斥
多個(gè)執(zhí)行流,訪問臨界資源的時(shí)候,具有一定順序性,叫做同步
系統(tǒng)中某些資源一次只允許一個(gè)進(jìn)程實(shí)用,這樣的稱謂臨界資源或互斥資源
在進(jìn)程中涉及到互斥資源的程序段叫臨界區(qū)。你寫的代碼=訪問臨界資源的代碼(臨界區(qū))+不訪問
臨界資源的代碼(?臨界區(qū))
•所謂的對(duì)共享資源進(jìn)?保護(hù),本質(zhì)是對(duì)訪問共享資源的代碼進(jìn)?保護(hù)
信號(hào)量
ipc資源必須刪除,否則不會(huì)自動(dòng)清除,除非重啟,所以system v ipc 資源的生命周期隨內(nèi)核變化而變化
信號(hào)量是一個(gè)計(jì)數(shù)器
- 作用方面:臨界保護(hù)區(qū)
- 本質(zhì)方面:資源的預(yù)定機(jī)制
操作??
- 申請(qǐng)資源,計(jì)數(shù)器–,P操作
- 釋放資源,計(jì)數(shù)器++,V操作
內(nèi)核是怎么組織管理IPC資源的

總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Centos7 Mysql 5.6 多主一從 解決方案與詳細(xì)配置
這篇文章主要介紹了Centos7 Mysql 5.6 多主一從 解決方案與詳細(xì)配置,需要的朋友可以參考下2016-04-04
詳解Linux環(huán)境下NodeJS的安裝配置(HelloWorld)
本篇文章主要介紹了Linux環(huán)境下NodeJS的安裝配置,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-01-01
ubuntu lighttpd+webpy (fastcgi)配置方法
首先安裝 lighttpd 和 webpy,因?yàn)橛?kpackagekit 做軟件管理,在安裝 webpy 的時(shí)候會(huì)自動(dòng)安裝 flup2009-07-07
Ubuntu 20.04 apt 更換國內(nèi)源的實(shí)現(xiàn)方法
這篇文章主要介紹了Ubuntu 20.04 apt 更換國內(nèi)源的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05

