有名管道FIFO

管道和FIFO的特徵之一是它們的數據是一個字節流。這是UNIX的原生I/O模型。進程往其中寫入的是字節流,系統不對它做解釋。linux

FIFO不存數據,只是經過它找到內核文件。安全

一.創建有名管道函數

1.命令mknod   :spa

mknod  name  p/s/m    //建立管道文件/信號量/共享內存code

2.命令mkfifo 建立管道blog

mkfifo -m 664 k2     //建立一個訪問權限爲664的管道文件k2 進程

3做爲函數:mkfifoip

#include <sys/types.h>內存

#include <sys/stat.h>字符串

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

【注意】

mkfifo已隱含指定O_CREAT|O_EXCL。即它要麼建立一個新的FIFO,要麼返回一個EEXIST錯誤。若是隻是但願打開而不建立文件,那就應調用open而不是mkfifo。

要打開一個已存在的FIFO或建立一個新的FIFO,應先調用mkfifo,檢查它是否返回EEXIST錯誤,若返回則改成調用open。

另:open函數

open(const char *path, O_RDONLY);//1
open(const char *path, O_RDONLY | O_NONBLOCK);//2
open(const char *path, O_WRONLY);//3
open(const char *path, O_WRONLY | O_NONBLOCK);//4

一、就是程序不能以O_RDWR(讀寫)模式打開FIFO文件進行讀寫操做,而其行爲也未明肯定義,由於如一個管道以讀/寫方式打開,進程就會讀回本身的輸出,同時咱們一般使用FIFO只是爲了單向的數據傳遞。

二、就是傳遞給open的是FIFO的路徑名,而不是文件名。

3.第二個參數中的選項O_NONBLOCK,選項O_NONBLOCK表示非阻塞,加上這個選項後,表示open調用是非阻塞的,若是沒有這個選項,則表示open調用是阻塞的。

以只讀方式和只寫方式打開文件時要注意:

讀端打開,若是寫端已打開則打開操做成功返回,若是寫端沒打開,則讀端阻塞。若是是非阻塞函數,則成功返回,(讀到文件結束標誌)

寫端打開,若是讀端已打開則打開操做成功返回,若是讀端沒打開,則寫端阻塞。若是是非阻塞函數,則返回ENXIO錯誤產生信號SIGPIPE

FIFO中讀取數據

1. 讀端的阻塞標誌只對本進程第一個讀操做施加做用,若是本進程內有多個讀操做序列,則在第一個讀操做被喚醒並完成讀操做後,其它將要執行的讀操做將再也不阻塞,即便在執行讀操做時,FIFO中沒有數據也同樣(此時,讀操做返回0)。

2. 對於設置了阻塞標誌的讀操做說,形成阻塞的緣由有兩種:當前FIFO內有數據,但有其它進程在讀這些數據;另外就是FIFO內沒有數據。解阻塞的緣由則是FIFO中有新的數據寫入,不論寫入數據量的大小,也不論讀操做請求多少數據量。就是說讀操做同時只能夠有一個進程進行。

3. 若是有進程寫打開FIFO,且當前FIFO內沒有數據,則對於設置了阻塞標誌的讀操做來講,將一直阻塞。對於沒有設置阻塞標誌讀操做來講則返回-1,當前errno值爲EAGAIN,提醒之後再試。

FIFO中寫入數據:

1.對於設置了阻塞標誌的寫操做:

  • 當要寫入的數據量不大於PIPE_BUF時,linux將保證寫入的原子性。若是此時管道空閒緩衝區不足以容納要寫入的字節數,則進入睡眠,直到當緩衝區中可以容納要寫入的字節數時,纔開始進行一次性寫操做。
  • 當要寫入的數據量大於PIPE_BUF時,linux將再也不保證寫入的原子性。FIFO緩衝區一有空閒區域,寫進程就會試圖向管道寫入數據,寫操做在寫完全部請求寫的數據後返回。(這時讀端可能間歇性獲得數據)

2.對於沒有設置阻塞標誌的寫操做:

  • 當要寫入的數據量不大於PIPE_BUF時,linux將保證寫入的原子性。若是當前FIFO空閒緩衝區可以容納請求寫入的字節數,寫完後成功返回;若是當前FIFO空閒緩衝區不可以容納請求寫入的字節數,則返回EAGAIN錯誤,提醒之後再寫;
  • 當要寫入的數據量大於PIPE_BUF時,linux將再也不保證寫入的原子性。在寫滿全部FIFO空閒緩衝區後,寫操做返回。

FIFO內核實現時能夠支持雙向通訊。(pipe單向通訊,由於父子進程共享同一個file 結構體

先關閉只讀方式打開的文件,再以只寫方式打開文件。這樣就能夠實現雙向通訊了。但最好使用一對FIFO

驗證代碼:

先寫後讀:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define MSG "hello"
int main()
{
    int fd;
    fd = open("./fio",O_WRONLY);
    printf("w:send msg:%s\n",MSG);
    write(fd,MSG,sizeof(MSG));
    sleep(5);
    close(fd);
    fd = open("./fio",O_RDONLY);
    char buf[1024];
    memset(buf,0,sizeof(buf));
    read(fd,buf,sizeof(buf));
    printf("w,recv:%s\n",buf);

}

先讀後寫:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main()
{
    int fd;
    fd = open("./fio",O_RDONLY);
    char buf[1024];
    memset(buf,0,sizeof(buf));
    read(fd,buf,sizeof(buf));
    printf("r:recv msg:%s\n",buf);

    sleep(5);
    close(fd);
    fd = open("./fio",O_WRONLY);
    printf("r:send:%s\n","fighting");
    write(fd,"fighting",9);

}

安全問題:

個FIFO文件,有多個進程同時向同一個FIFO文件寫數據,而只有一個讀FIFO進程在同一個FIFO文件中讀取數據時,會發生數據塊的相互交錯。

根據上面的知識咱們知道:

若是全部的寫請求都是發往一個阻塞的FIFO的,而且每一個寫記請求的數據長度小於等於PIPE_BUF字節,系統就能夠確保數據決不會交錯在一塊兒。

模型:

1-1

n-1

n-1-n

 fgets,它讀取以換行符「\n」結尾的字符串.

小結:

管道文件。它佔用i節點塊和數據塊,在目錄文件中記載了文件和i節點對應關係的管道是有名管道,沒有記載的是無名管道。

管道文件一旦讀出,就從管道中刪除,因此它具備不可再現性。

相關文章
相關標籤/搜索