進程間通信方式之有名管道

在上一篇介紹了進程間通信方式之管道,鏈接如下:
http://blog.csdn.net/zhuyunfei/article/details/51087802
今天再來介紹下進程間通信方式之有名管道

1.有名管道
看名字就和明顯了,它和匿名管道的區別就是,這個管道是有“名字”,這個名字是什麼呢?就是FIFO文件路徑,從文件操作我們可以大膽推理,既然有文件路徑,那麼這個文件就可以被不同的進程所訪問,這樣就實現了通過有名管道來實現不同進程間的通信,此時,有名管道就不再像匿名管道那樣受限制,之前的匿名管道只能在具有親緣關係的進程中通信,匿名管道不適用不具有親緣關係的不同進程間通信。
有名管道也稱爲命名管道(named pipe),或者FIFO。
創建有名管道的函數是mkfifo,函數原型是:
int mkfifo (const char *__path, __mode_t __mode)
功能:創建新的帶命名路徑的FIFO
參數:path — 命名管道路徑
mode — 模式權限
返回值:成功返回0,失敗返回-1;

包含mkfifo定義的頭文件路徑是:/usr/include/x86_64-linux-gnu/sys/stat.h

2.有名管道的特點
a)使不同進程之間完成通信。
通過mkfifo創建FIFO文件建立有名管道,
使得不同進程可以通過像訪問文件的方式一樣來訪問有名管道,
fifo文件特點:
先進先出:即寫文件從有名管道數據尾端寫入,數據讀取從有名管道的開始處讀取
b)有名管道內數據不支持如lseek()文件定位操作

3.阻塞打開與非阻塞打開
對於讀進程
  •若該管道是阻塞打開,且當前FIFO內沒有數據,則對讀進程而言將一直阻塞到有數據寫入
  •若該管道是非阻塞打開,則不論FIFO內是否有數據,讀進程都會立即執行讀操作。即如果FIFO內沒有數據,則讀函數將立刻返回0
對於寫進程
  •若該管道是阻塞打開,則寫操作將一直阻塞到數據可以被寫入
  •若該管道是非阻塞打開而不能寫入全部數據,則讀操作進行部分寫入或者調用失敗

4.例子
writepipe.c

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

#define P_FIFO "/tmp/name_pipe"

int main(int argc, char* argv[])
{
    int fd;
    //命令要帶寫入有名管道的數據
    if(argc < 2){
        printf("please input the write data.\n");
    }
    //打開有名管道
    //第一個參數指定有名管道路徑
    //第二個參數指定以寫以及非阻塞方式打開有名管道
    //O_WRONLY寫入方式
    //O_NONBLOCK阻塞模式
    fd = open(P_FIFO,O_WRONLY|O_NONBLOCK);
    //打開有名管道失敗
    if(fd < 0){
        printf("open failed.\n");
    }
    //寫入數據到有名管道
    //第一個參數爲有名管道文件描述符
    //第二個參數爲寫入有名管道的數據
    //第三個參數爲寫入有名管道的數據長度
    write(fd,argv[1],100);
    //關閉有名管道
    close(fd);

    return 0;
}

readpipe.c

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

#define P_FIFO "/tmp/name_pipe"

int main()
{
    int ret = -1;
    int fd;
    char buffer[100];

    //如果有名管道存在,則先刪除它
    if(access(P_FIFO,F_OK)){    
        execlp("rm","-f",P_FIFO,NULL);
        printf("access.\n");
    }

    //創建有名管道,並賦予訪問有名管道的權限
    ret = mkfifo(P_FIFO,0777);

    //創建失敗
    if(ret < 0){
        printf("create named pipe failed.\n");
        return 0;
    }
    //打開有名管道
    //第一個參數爲有名管道文件路徑
    //第二個參數表明是以讀取方式並以非阻塞方式打開有名管道
    //O_RDONLY讀取模式
    //O_NONBLOCK非阻塞方式
    fd = open(P_FIFO,O_RDONLY | O_NONBLOCK);
    //循環讀取有名管道
    while(1){   
        memset(buffer,0,sizeof(buffer));
        if(read(fd,buffer,100) == 0){   
            printf("nodata.\n");
        }else{
            printf("getdata:%s\n",buffer);
            sleep(1);
        }
    }
    close(fd);

    return 0;
}

編譯這兩個程序

sudo gcc readpipe.c -o readpipe
sudo gcc writepipe.c -o writepipe

如果需要加權限,

sudo chmod 777 readpipe
sudo chmod 777 writepipe

這時我們先運行readpipe進程,然後運行writepipe進程,並帶一個數據參數hellonamedpipe,這時我們在readpipe進程窗口會看見它讀出了writepipe進程寫入到有名管道中的數據,結果如圖:
這裏寫圖片描述

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