本文關鍵字: linux 管道通信,linux 進程通信方式,有名管道,FIFO
有名管道的創建可以使用函數mkfifo(),該函數類似于文件中的open()操作,可以指定管道的路徑和打開的模式。用戶還可以在命令行使用“mknod 管道名 p”來創建有名管道。
在創建管道成功后,就可以使用open()、read()和write()這些函數了。與普通文件的開發設置一樣,對于為讀而打開的管道可在open()中設置O_RDONLY,對于為寫而打開的管道可在open()中設置O_WRONLY,在這里與普通文件不同的是阻塞問題。由于普通文件在讀寫時不會出現阻塞問題,而在管道的讀寫中卻有阻塞的可能,這里的非阻塞標志可以在open()函數中設定為O_NONBLOCK。下面分別對阻塞打開和非阻塞打開的讀寫進行討論。
對于讀進程:
● 若該管道是阻塞打開,且當前FIFO內沒有數據,則對讀進程而言將一直阻塞到有數據寫入。
● 若該管道是非阻塞打開,則不論FIFO內是否有數據,讀進程都會立即執行讀操作。即如果FIFO內沒有數據,則讀函數將立刻返回0。
對于寫進程:
● 若該管道是阻塞打開,則寫操作將一直阻塞到數據可以被寫入。
● 若該管道是非阻塞打開而不能寫入全部數據,則讀操作進行部分寫入或者調用失敗。
表1列出了mkfifo()函數的語法要點。
表1 mkfifo()函數語法要點
所需頭文件 |
#include <sys/types.h>
#include <sys/state.h>
|
函數原型 |
int mkfifo(const char *filename,mode_t mode) |
函數傳入值 |
filename:要創建的管道 |
mode |
O_RDONLY:讀管道 |
O_WRONLY:寫管道 |
O_RDWR:讀寫管道 |
O_NONBLOCK:非阻塞 |
O_CREAT:如果該文件不存在,那么就創建一個新的文件,并用第3個參數為其設置權限 |
O_EXCL:如果使用O_CREAT時文件存在,那么可返回錯誤消息。這個參數可測試文件是否存在 |
函數返回值 |
成功:0 |
出錯:-1 |
表2再對FIFO相關的出錯信息進行歸納,以方便用戶查錯。
表2 FIFO相關的出錯信息
EACCESS |
參數filename所指定的目錄路徑無可執行的權限 |
EEXIST |
參數filename所指定的文件已存在 |
ENAMETOOLONG |
參數filename的路徑名稱太長 |
ENOENT |
參數filename包含的目錄不存在 |
ENOSPC |
文件系統的剩余空間不足 |
ENOTDIR |
參數filename路徑中的目錄存在但卻非真正的目錄 |
EROFS |
參數filename指定的文件存在于只讀文件系統內 |
下面的實例包含兩個程序,一個用于讀管道,另一個用于寫管道。其中在讀管道的程序中創建管道,并且作為main()函數里的參數由用戶輸入要寫入的內容;讀管道的程序會讀出用戶寫入到管道的內容。這兩個程序采用的是阻塞式讀寫管道模式。
寫管道的程序如下:
/* fifo_write.c */
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MYFIFO "/tmp/myfifo" /* 有名管道文件名 */
#define MAX_BUFFER_SIZE PIPE_BUF /* 定義在limits.h中 */
int main(int argc, char * argv[]) /* 參數為即將寫入的字符串 */
{
int fd;
char buff[MAX_BUFFER_SIZE];
int nwrite;
if(argc <= 1)
{
printf("Usage: ./fifo_write string\n");
exit(1);
}
sscanf(argv[1], "%s", buff);
/* 以只寫阻塞方式打開FIFO管道 */
fd = open(MYFIFO, O_WRONLY);
if (fd == -1)
{
printf("Open fifo file error\n");
exit(1);
}
/* 向管道中寫入字符串 */
if ((nwrite = write(fd, buff, MAX_BUFFER_SIZE)) > 0)
{
printf("Write '%s' to FIFO\n", buff);
}
close(fd);
exit(0);
}
讀管道程序如下:
/* fifo_read.c */
(頭文件和宏定義同fifo_write.c)
int main()
{
char buff[MAX_BUFFER_SIZE];
int fd;
int nread;
/* 判斷有名管道是否已存在,若尚未創建,則以相應的權限創建 */
if (access(MYFIFO, F_OK) == -1)
{
if ((mkfifo(MYFIFO, 0666) < 0) && (errno != EEXIST))
{
printf("Cannot create fifo file\n");
exit(1);
}
}
/* 以只讀阻塞方式打開有名管道 */
fd = open(MYFIFO, O_RDONLY);
if (fd == -1)
{
printf("Open fifo file error\n");
exit(1);
}
while (1)
{
memset(buff, 0, sizeof(buff));
if ((nread = read(fd, buff, MAX_BUFFER_SIZE)) > 0)
{
printf("Read '%s' from FIFO\n", buff);
}
}
close(fd);
exit(0);
}
為了能夠較好地觀察運行結果,需要把這兩個程序分別在兩個終端里運行,在這里首先啟動讀管道程序。讀管道進程在建立管道后就開始循環地從管道里讀出內容,如果沒有數據可讀,則一直阻塞到寫管道進程向管道寫入數據。在啟動了寫管道程序后,讀進程能夠從管道里讀出用戶的輸入內容,程序運行結果如下。
終端一:
$ ./fifo_read
Read 'FIFO' from FIFO
Read 'Test' from FIFO
Read 'Program' from FIFO
…
終端二:
$ ./fifo_write FIFO
Write 'FIFO' to FIFO
$ ./fifo_write Test
Write 'Test' to FIFO
$ ./fifo_write Program
Write 'Program' to FIFO
…
本文選自華清遠見嵌入式培訓教材《從實踐中學嵌入式Linux應用程序開發》
熱點鏈接:
1、標準流管道
2、無名管道系統調用
3、Linux下進程間通信方式-管道
4、Linux下進程間通信
5、實驗:編寫守護進程
更多新聞>> |