Linux進(jìn)程通信 | 管道與FIFO

Linux進(jìn)程間通信通常使用的方式有很多種别惦,其中比較常用的包括管道(pipe)和 FIFO(命名管道)潭枣。本文將介紹這兩種通信方式的基本概念绞蹦,并用C語言編寫示例代碼拳恋,來說明如何在兩個(gè)進(jìn)程之間使用這些IPC機(jī)制進(jìn)行通信氮发。

管道(pipe)

管道是一種半雙工的通信方式渴肉,用于父進(jìn)程和子進(jìn)程之間的通信。在 Linux 中爽冕,管道是一種特殊的文件仇祭,有兩個(gè)端點(diǎn),一個(gè)讀端和一個(gè)寫端颈畸。管道的基本操作包括創(chuàng)建管道乌奇、關(guān)閉文件描述符、讀取數(shù)據(jù)和寫入數(shù)據(jù)等眯娱。

創(chuàng)建管道

在 Linux 中礁苗,我們可以使用 pipe() 系統(tǒng)調(diào)用來創(chuàng)建管道。pipe() 函數(shù)的原型如下:

#include <unistd.h>
int pipe(int pipefd[2]);

其中徙缴,pipefd 是一個(gè)數(shù)組试伙,用于存儲(chǔ)管道的讀端和寫端的文件描述符。pipe() 函數(shù)成功時(shí)返回 0,失敗時(shí)返回 -1疏叨。

下面是一個(gè)創(chuàng)建管道的示例代碼:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    int pipefd[2];
    
    // 創(chuàng)建管道
    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }
    
    printf("讀端文件描述符:%d\n", pipefd[0]);
    printf("寫端文件描述符:%d\n", pipefd[1]);
    
    exit(EXIT_SUCCESS);
}

  • 編譯并運(yùn)行吱抚,打印如下
讀端文件描述符:3
寫端文件描述符:4

管道的讀寫

在使用管道進(jìn)行通信時(shí),父進(jìn)程和子進(jìn)程可以通過管道進(jìn)行數(shù)據(jù)的讀取和寫入考廉。在 C 語言中秘豹,我們可以使用 read()函數(shù)和 write() 函數(shù)來讀取和寫入數(shù)據(jù)。read() 函數(shù)用于從管道中讀取數(shù)據(jù)昌粤,write() 函數(shù)用于向管道中寫入數(shù)據(jù)既绕,使用 close() 函數(shù)關(guān)閉文件描述符。在管道的使用中涮坐,我們應(yīng)該在不需要的時(shí)候關(guān)閉管道的讀端和寫端凄贩,以避免資源浪費(fèi)。

這三個(gè)函數(shù)的原型分別如下:

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
int close(int fd);

下面是一個(gè)父進(jìn)程向子進(jìn)程寫入數(shù)據(jù)并讀取返回結(jié)果的示例代碼:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>

#define BUF_SIZE 1024

int main()
{
    int pipefd[2];
    pid_t pid;
    char buf[BUF_SIZE];
    int status;
    
    // 創(chuàng)建管道
    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }
    
    // 創(chuàng)建子進(jìn)程
    pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    
    if (pid == 0) { // 子進(jìn)程        
        // 從管道中讀取數(shù)據(jù)
        if (read(pipefd[0], buf, BUF_SIZE) == -1) {
            perror("read");
            exit(EXIT_FAILURE);
        }
        
        printf("子進(jìn)程收到消息:%s\n", buf);
        
        // 發(fā)送消息給父進(jìn)程
        const char* message = "Hello, parent!";
        if (write(pipefd[1], message, strlen(message) + 1) == -1) {
            perror("write");
            exit(EXIT_FAILURE);
        }
        close(pipefd[1]); // 關(guān)閉寫端
        exit(EXIT_SUCCESS);
    } else { // 父進(jìn)程 
        // 發(fā)送消息給子進(jìn)程
        const char* message = "Hello, child!";
        if (write(pipefd[1], message, strlen(message) + 1) == -1) {
            perror("write");
            exit(EXIT_FAILURE);
        }
        
        // 等待子進(jìn)程退出
        wait(&status);
        if (WIFEXITED(status)) {
            printf("子進(jìn)程退出袱讹,返回值:%d\n", WEXITSTATUS(status));
        }
        
        // 從管道中讀取數(shù)據(jù)
        if (read(pipefd[0], buf, BUF_SIZE) == -1) {
            perror("read");
            exit(EXIT_FAILURE);
        }
        printf("父進(jìn)程收到消息:%s\n", buf);
        close(pipefd[0]); // 關(guān)閉讀端
        
        exit(EXIT_SUCCESS);
    }
}

在這個(gè)示例代碼中疲扎,父進(jìn)程先向子進(jìn)程發(fā)送一條消息,子進(jìn)程收到消息后向父進(jìn)程發(fā)送一條消息捷雕,并退出椒丧。父進(jìn)程在等待子進(jìn)程退出后再從管道中讀取子進(jìn)程發(fā)送的消息。

  • 編譯并運(yùn)行救巷,打印如下
子進(jìn)程收到消息:Hello, child!
子進(jìn)程退出壶熏,返回值:0
父進(jìn)程收到消息:Hello, parent!

FIFO(命名管道)

FIFO(命名管道)是一種文件系統(tǒng)對(duì)象,與管道類似浦译,也可以用于進(jìn)程間通信棒假。FIFO 是一種特殊類型的文件,它可以在文件系統(tǒng)中被創(chuàng)建精盅,并且進(jìn)程可以通過文件描述符來讀取和寫入數(shù)據(jù)帽哑。

與管道不同的是,F(xiàn)IFO 可以被多個(gè)進(jìn)程打開叹俏,并且可以在文件系統(tǒng)中以路徑的形式存在妻枕,因此不像管道那樣只能在具有親緣關(guān)系的進(jìn)程之間使用。任何進(jìn)程只要有相應(yīng)的權(quán)限就可以打開 FIFO 并進(jìn)行通信她肯。

FIFO 的創(chuàng)建和使用

FIFO 的創(chuàng)建和使用也比較簡(jiǎn)單佳头。首先需要使用 mkfifo() 函數(shù)創(chuàng)建 FIFO 文件鹰贵,其原型如下

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);

其中晴氨,pathname 是 FIFO 文件的路徑名,mode 是文件的權(quán)限碉输。

創(chuàng)建 FIFO 文件后籽前,就可以像使用普通文件一樣打開它,并使用 read() 和 write() 函數(shù)進(jìn)行數(shù)據(jù)的讀寫。

下面是一個(gè)使用 FIFO 進(jìn)行進(jìn)程間通信的示例代碼:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define FIFO_PATH "/tmp/myfifo"
#define BUF_SIZE 1024

int main()
{
    int fd;
    char buf[BUF_SIZE];
    
    // 創(chuàng)建 FIFO 文件
    if (mkfifo(FIFO_PATH, 0666) == -1) {
        perror("mkfifo");
        exit(EXIT_FAILURE);
    }
    
    // 打開 FIFO 文件
    fd = open(FIFO_PATH, O_RDWR);
    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }
    
    // 向 FIFO 中寫入數(shù)據(jù)
    const char* message = "Hello, world!";
    if (write(fd, message, strlen(message) + 1) == -1) {
        perror("write");
        exit(EXIT_FAILURE);
    }
    
    // 從 FIFO 中讀取數(shù)據(jù)
    if (read(fd, buf, BUF_SIZE) == -1) {
        perror("read");
        exit(EXIT_FAILURE);
    }
    
    printf("收到消息:%s\n", buf);
    
    // 關(guān)閉文件描述符并刪除 FIFO 文件
    close(fd);
    if (unlink(FIFO_PATH) == -1) {
        perror("unlink");
        exit(EXIT_FAILURE);
    }
    
    exit(EXIT_SUCCESS);
}

在這個(gè)示例代碼中枝哄,程序先創(chuàng)建了一個(gè) FIFO 文件 /tmp/myfifo肄梨,然后打開該文件并向其中寫入一條消息。接下來從 FIFO 文件中讀取數(shù)據(jù)挠锥,并將其打印出來众羡。最后關(guān)閉文件描述符并刪除 FIFO 文件。

  • 編譯并運(yùn)行蓖租,打印如下
收到消息:Hello, world!

小結(jié)

Linux 中管道和 FIFO 是進(jìn)程間通信的重要方式粱侣。管道只能用于親緣關(guān)系的進(jìn)程間通信,而 FIFO 可以被多個(gè)進(jìn)程打開蓖宦,不受進(jìn)程之間關(guān)系的限制齐婴。無論是管道還是 FIFO,它們的使用方式都與普通文件類似稠茂,需要使用文件描述符和 read()柠偶、write() 函數(shù)來進(jìn)行數(shù)據(jù)的讀寫。

在使用管道和 FIFO 進(jìn)行進(jìn)程間通信時(shí)睬关,需要注意以下幾點(diǎn):

  1. 管道和 FIFO 只能用于同一主機(jī)上的進(jìn)程間通信诱担,不能用于跨主機(jī)通信。
  2. 管道和 FIFO 的讀寫操作是阻塞的电爹,這意味著當(dāng)一個(gè)進(jìn)程嘗試從一個(gè)空管道或 FIFO 中讀取數(shù)據(jù)時(shí)该肴,它會(huì)被阻塞,直到有數(shù)據(jù)可用為止藐不。同樣匀哄,當(dāng)一個(gè)進(jìn)程嘗試將數(shù)據(jù)寫入一個(gè)滿的管道或 FIFO 時(shí),它也會(huì)被阻塞雏蛮,直到有空閑空間為止涎嚼。
  3. 在使用管道和 FIFO 進(jìn)行進(jìn)程間通信時(shí),需要注意文件描述符的關(guān)閉順序挑秉。
  4. 管道和 FIFO 只能傳輸字節(jié)流法梯,不能傳輸其他類型的數(shù)據(jù),如結(jié)構(gòu)體或指針犀概。
  5. 如果使用管道或 FIFO 進(jìn)行進(jìn)程間通信時(shí)立哑,數(shù)據(jù)量較大,需要進(jìn)行分段傳輸姻灶,否則可能會(huì)導(dǎo)致阻塞或緩沖區(qū)溢出等問題铛绰。
  6. 管道和 FIFO 都是單向的,如果需要雙向通信产喉,則需要建立兩個(gè)管道或 FIFO捂掰。

以上敢会,如果覺得對(duì)你有幫助,點(diǎn)個(gè)贊再走吧这嚣,這樣@知微之見也有更新下去的動(dòng)力鸥昏!

也歡迎私信我,一起交流姐帚!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吏垮,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子罐旗,更是在濱河造成了極大的恐慌惫皱,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尤莺,死亡現(xiàn)場(chǎng)離奇詭異旅敷,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)颤霎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門媳谁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人友酱,你說我怎么就攤上這事晴音。” “怎么了缔杉?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵锤躁,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我或详,道長(zhǎng)系羞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任霸琴,我火速辦了婚禮椒振,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘梧乘。我一直安慰自己澎迎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布选调。 她就那樣靜靜地躺著夹供,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仁堪。 梳的紋絲不亂的頭發(fā)上哮洽,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音枝笨,去河邊找鬼袁铐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛横浑,可吹牛的內(nèi)容都是我干的剔桨。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼徙融,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼洒缀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起欺冀,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤树绩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后隐轩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饺饭,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年职车,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瘫俊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡悴灵,死狀恐怖扛芽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情积瞒,我是刑警寧澤川尖,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站茫孔,受9級(jí)特大地震影響叮喳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缰贝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一嘲更、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧揩瞪,春花似錦赋朦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嗤攻,卻和暖如春毛嫉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背妇菱。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工承粤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留暴区,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓辛臊,卻偏偏與公主長(zhǎng)得像仙粱,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子彻舰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容