UNIX高級編程總結-----進程間通信(FIFO---有名管道)

1、簡介

        對於普通的未命名pipe,兩個不相關的進程是無法通信的。但是對於命名通道FIFO而言,即便是兩個不相關的進程也可以實現進程間通信。

2、操作 FIFO

        FIFO在文件系統中表現爲一個文件,大部分的系統文件調用都可以用在FIFO上面,比如:read,open,write,close,unlink,stat等函數。但是seek等函數不能對FIFO調用。

        可以調用open函數打開命名管道,但是有兩點要注意
1)不能以O_RDWR模式打開命名管道FIFO文件,否則其行爲是未定義的,管道是單向的,不能同時讀寫;
2)就是傳遞給open調用的是FIFO的路徑名,而不是正常的文件

        打開FIFO文件通常有四種方式:
open(pathname, O_RDONLY);           //1 只讀、阻塞模式
open(pathname, O_RDONLY | O_NONBLOCK);    //2 只讀、非阻塞模式
open(pathname, O_WRONLY);          //3 只寫、阻塞模式
open(pathname, O_WRONLY | O_NONBLOCK);   //只寫、非阻塞模式

        注意阻塞模式open打開FIFO:
1)當以阻塞、只讀模式打開FIFO文件時,將會阻塞,直到其他進程以寫方式打開訪問文件;
2)當以阻塞、只寫模式打開FIFO文件時,將會阻塞,直到其他進程以讀方式打開文件;
3)當以非阻塞方式(指定O_NONBLOCK)方式只讀打開FIFO的時候,則立即返回。當只寫open時,如果沒有進程爲讀打開FIFO,則返回-1,其errno是ENXIO。

3、代碼使用操作

(1)阻塞管道讀寫

Read進程代碼如下:

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

int main(int argc, char* argv[])
{
    int ret = mkfifo("my_fifo",0777);
    if (ret == -1)
    {
        printf("make fifo failed!\n");
        return 1;
    }

    char buf[256] = {0};
    int fd = open("my_fifo",O_RDONLY);
    read(fd,buf,256);
    printf("%s\n",buf);
    close(fd);
    unlink("my_fifo");
    return 0;
}

Write進程代碼如下:

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

int main(int argc, char* argv[])
{
    char *buf = "i am write process\n";
    int fd = open("my_fifo",O_WRONLY);
    write(fd,buf,strlen(buf));
    close(fd);
    return 0;
}

首先啓動read進程,創建fifo,當前目錄下會生出一個名字爲“my_fifo”的文件,然後啓動write進程,運行結果如下: 

結論:當write進程沒有以O_WRONLY模式open命名管道時,read進程在以O_RDONLY模式open命名管道的時候會阻塞。反過來也是這樣。

(2)非阻塞管道讀寫

Read進程代碼如下:

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

int main(int argc, char* argv[])
{
    int ret = mkfifo("my_fifo",0777);
    if (ret == -1)
    {
        printf("make fifo failed!\n");
        return 1;
    }

    char buf[256] = {0};
    int fd = open("my_fifo",O_RDONLY | O_NONBLOCK);
   // sleep(5);  
    read(fd,buf,256);
    printf("%s\n",buf);
    close(fd);
    unlink("my_fifo");
    return 0;
}

Write進程代碼如下:

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

int main(int argc, char* argv[])
{
    char *buf = "i am write process\n";
    int fd = open("my_fifo",O_WRONLY | O_NONBLOCK);
    write(fd,buf,strlen(buf));
    close(fd);
    return 0;
}

直接啓動Read進程,open函數將不會阻塞,read函數讀取到0個字節數據,程序退出。

將sleep(5)的註釋去掉,再次啓動Read進程,馬上啓動Write進程,Read進程會讀取到Write進程寫入fifo的數據並打印,然後退出。

結論:flags=O_RDONLY|O_NONBLOCK:如果此時沒有其他進程以寫的方式打開FIFO,open也會成功返回,此時FIFO被讀打開,而不會返回錯誤。

經測試:flags=O_WRONLY|O_NONBLOCK:立即返回,如果此時沒有其他進程以讀的方式打開,open會失敗打開,此時FIFO沒有被打開,返回-1。

 

文章引用:Linux進程間通信-命名管道深入理解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章