有名管道(FIFO)
有名管道也被稱為FIFO檔案,是一種特殊的檔案。由于linux所有的事物都可以被視為檔案,是以對有名管道的使用也就變得與檔案操作非常統一。
(1)建立有名管道
用如下兩個函數中的其中一個,可以建立有名管道。
#include
#include
int mkfifo(const char *filename, mode_t mode);
filname是指檔案名,而mode是指定檔案的讀寫權限。
(2)打開有名管道
和打開其他檔案一樣,可以用open來打開。通常有四種方法:
open(const char *path, O_RDONLY);
open(const char *path, O_RDONLY | O_NONBLOCK);
open(const char *path, O_WRONLY);
open(const char *path, O_WRONLY | O_NONBLOCK);
有三點要注意:
1就是程式不能以O_RDWR(讀寫)模式打開FIFO檔案進行讀寫操作,而其行為也未明确定義,因為如一個管道以讀/寫方式打開,程序就會讀回自己的輸出,同時我們通常使用FIFO隻是為了單向的資料傳遞。
2就是傳遞給open調用的是FIFO的路徑名,而不是正常的檔案。(如:
const char *fifo_name = "/tmp/my_fifo";)
3第二個參數中的選項O_NONBLOCK,選項O_NONBLOCK表示非阻塞,加上這個選項後,表示open調用是非阻塞的,如果沒有這個選項,則表示open調用是阻塞的。
(3)阻塞問題
對于以隻讀方式(O_RDONLY)打開的FIFO檔案,如果open調用是阻塞的(即第二個參數為O_RDONLY),除非有一個程序以寫方式打開同一個FIFO,否則它不會傳回;如果open調用是非阻塞的的(即第二個參數為O_RDONLY | O_NONBLOCK),則即使沒有其他程序以寫方式打開同一個FIFO檔案,open調用将成功并立即傳回。
對于以隻寫方式(O_WRONLY)打開的FIFO檔案,如果open調用是阻塞的(即第二個參數為O_WRONLY),open調用将被阻塞,直到有一個程序以隻讀方式打開同一個FIFO檔案為止;如果open調用是非阻塞的(即第二個參數為O_WRONLY | O_NONBLOCK),open總會立即傳回,但如果沒有其他程序以隻讀方式打開同一個FIFO檔案,open調用将傳回-1,并且FIFO也不會被打開。
(4)使用FIFO實作程序間的通信
管道的寫入端從一個檔案讀出資料,然後寫入寫管道。管道的讀取端從管道讀出後寫到檔案中。
寫入端代碼:fifowrite.c
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
const char *fifo_name = "/tmp/my_fifo";
int pipe_fd = -1;
int data_fd = -1;
int res = 0;
const int open_mode = O_WRONLY;
int bytes_sent = 0;
char buffer[PIPE_BUF + 1];
int bytes_read = 0;
if(access(fifo_name, F_OK) == -1)
{
printf ("Create the fifo pipe.\n");
res = mkfifo(fifo_name, 0777);
if(res != 0)
{
fprintf(stderr, "Could not create fifo %s\n", fifo_name);
exit(EXIT_FAILURE);
}
}
printf("Process %d opening FIFO O_WRONLY\n", getpid());
pipe_fd = open(fifo_name, open_mode);
printf("Process %d result %d\n", getpid(), pipe_fd);
if(pipe_fd != -1)
{
bytes_read = 0;
data_fd = open("Data.txt", O_RDONLY);
if (data_fd == -1)
{
close(pipe_fd);
fprintf (stderr, "Open file[Data.txt] failed\n");
return -1;
}
bytes_read = read(data_fd, buffer, PIPE_BUF);
buffer[bytes_read] = '\0';
while(bytes_read > 0)
{
res = write(pipe_fd, buffer, bytes_read);
if(res == -1)
{
fprintf(stderr, "Write error on pipe\n");
exit(EXIT_FAILURE);
}
bytes_sent += res;
bytes_read = read(data_fd, buffer, PIPE_BUF);
buffer[bytes_read] = '\0';
}
close(pipe_fd);
close(data_fd);
}
else
exit(EXIT_FAILURE);
printf("Process %d finished\n", getpid());
exit(EXIT_SUCCESS);
}
管道讀取端: fiforead.c
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
const char *fifo_name = "/tmp/my_fifo";
int pipe_fd = -1;
int data_fd = -1;
int res = 0;
int open_mode = O_RDONLY;
char buffer[PIPE_BUF + 1];
int bytes_read = 0;
int bytes_write = 0;
memset(buffer, '\0', sizeof(buffer));
printf("Process %d opening FIFO O_RDONLY\n", getpid());
pipe_fd = open(fifo_name, open_mode);
data_fd = open("DataFormFIFO.txt", O_WRONLY|O_CREAT, 0644);
if (data_fd == -1)
{
fprintf(stderr, "Open file[DataFormFIFO.txt] failed\n");
close(pipe_fd);
return -1;
}
printf("Process %d result %d\n",getpid(), pipe_fd);
if(pipe_fd != -1)
{
do
{
res = read(pipe_fd, buffer, PIPE_BUF);
bytes_write = write(data_fd, buffer, res);
bytes_read += res;
}while(res > 0);
close(pipe_fd);
close(data_fd);
}
else
exit(EXIT_FAILURE);
printf("Process %d finished, %d bytes read\n", getpid(), bytes_read);
exit(EXIT_SUCCESS);
}
(5)有名管道的安全問題
有一種情況是:一個FIFO檔案,有多個程序同時向同一個FIFO檔案寫資料,而隻有一個讀FIFO程序在同一個FIFO檔案中讀取資料時,會發生資料塊的互相交錯。不同程序向一個FIFO讀程序發送資料是很普通的情況。這個問題的解決方法,就是讓寫操作的原子化。系統規定:在一個以O_WRONLY(即阻塞方式)打開的FIFO中, 如果寫入的資料長度小于等待PIPE_BUF,那麼或者寫入全部位元組,或者一個位元組都不寫入。如果所有的寫請求都是發往一個阻塞的FIFO的,并且每個寫記請求的資料長度小于等于PIPE_BUF位元組,系統就可以確定資料決不會交錯在一起。
嵌入式物聯網需要學的東西真的非常多,千萬不要學錯了路線和内容,導緻工資要不上去!
無償分享大家一個資料包,差不多150多G。裡面學習内容、面經、項目都比較新也比較全!某魚上買估計至少要好幾十。加微信領取資料