管道
文章目錄
- 1 無名管道
- 1.1 用法
- 1.2 使用示例
- 2 有名管道
- 2.1 mkfifo函數(shù)介紹
- 2.2 示例
1 無名管道
1.1 用法
pipe函數(shù):
頭文件:
#include <unistd.h>函數(shù)原型:
int pipe(int pipefd[2]);返回值:
- 成功:0
- 失敗:-1
特點:
- 特殊文件(沒有名字),無法使用open,但是可以使用close。
- 只能通過子進程繼承文件描述符的形式來使用
- write和read操作可能會阻塞進程
- 所有文件描述符被關閉之后,無名管道被銷毀
使用步驟:
- 父進程pipe無名管道
- fork子進程
- close無用端口
- write/read讀寫端口
- close讀寫端口
1.2 使用示例
#include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h>#define MAX_DATA_LEN 256 #define DELAY_TIME 1int main() {pid_t pid;int pipe_fd[2];char buf[MAX_DATA_LEN];const char data[] = "Pipe Test Program";int real_read, real_write;memset((void*)buf, 0, sizeof(buf));/* 創(chuàng)建管道 */if (pipe(pipe_fd) < 0){printf("pipe create error\n");exit(1);}/* 創(chuàng)建一子進程 */if ((pid = fork()) == 0){/* 子進程關閉寫描述符,并通過使子進程暫停 3s 等待父進程已關閉相應的讀描述符 */close(pipe_fd[1]);sleep(DELAY_TIME * 3);/* 子進程讀取管道內容 */if ((real_read = read(pipe_fd[0], buf, MAX_DATA_LEN)) > 0){printf("%d bytes read from the pipe is '%s'\n", real_read, buf);}/* 關閉子進程讀描述符 */close(pipe_fd[0]);exit(0);}else if (pid > 0){/* 父進程關閉讀描述符,并通過使父進程暫停 1s 等待子進程已關閉相應的寫描述符 */close(pipe_fd[0]);sleep(DELAY_TIME);if((real_write = write(pipe_fd[1], data, strlen(data))) != -1){printf("Parent write %d bytes : '%s'\n", real_write, data);}/*關閉父進程寫描述符*/close(pipe_fd[1]);/*收集子進程退出信息*/waitpid(pid, NULL, 0);exit(0);} }2 有名管道
2.1 mkfifo函數(shù)介紹
mkfifo函數(shù):
頭文件:
#include <sys/types.h> #include <sys/state.h>函數(shù)原型:
int mkfifo(const char *filename,mode_t mode)返回值:
- 成功:0
- 失敗:-1
特點:
- 有文件名,可以使用open函數(shù)打開
- 任意進程間數(shù)據(jù)傳輸
- write和read操作可能會阻塞進程
- write具有"原子性"
使用步驟:
- 第一個進程mkfifo有名管道
- open有名管道,write/read數(shù)據(jù)
- close有名管道
- 第二個進程open有名管道,read/write數(shù)據(jù)
- close有名管道
2.2 示例
/**fifo.c *//*** 無名管道,它只能用于具有親緣關系的進程之間,這就大大地限制了管道的使用。有名管道的出現(xiàn)突破了這種限制, 它可以使互不相關的兩個進程實現(xiàn)彼此通信。 * 該管道可以通過路徑名來指出,并且在文件系統(tǒng)中是可見的。在建立了管道之后,兩個進程就可以把它當作普通文件一樣進行讀寫操作,使用非常方便。* 不過 FIFO 是嚴格地遵循先進先出規(guī)則的,對管道及 FIFO 的讀總是從開始處返回數(shù)據(jù),對它們的寫則把數(shù)據(jù)添加到末尾,它們不支持如 lseek()等文件定位操作。* 有名管道的創(chuàng)建可以使用函數(shù) mkfifo(),該函數(shù)類似文件中的 open()操作,可以指定管道的路徑和打開的模式* * 在創(chuàng)建管道成功之后,就可以使用 open()、 read()和 write()這些函數(shù)了。與普通文件的開發(fā)設置一樣,對于為讀而打開的管道可在 open()中設置 O_RDONLY,* 對于為寫而打開的管道可在 open()中設置 O_WRONLY,在這里與普通文件不同的是阻塞問題。由于普通文件的讀寫時不會出現(xiàn)阻塞問題,而在管道的讀寫中卻有阻塞的可能,* 這里的非阻塞標志可以在 open()函數(shù)中設定為 O_NONBLOCK。下面分別對阻塞打開和非阻塞打開的讀寫進行討論。* (1)對于讀進程。* ? 若該管道是阻塞打開,且當前 FIFO 內沒有數(shù)據(jù),則對讀進程而言將一直阻塞到有數(shù)據(jù)寫入。* ? 若該管道是非阻塞打開,則不論 FIFO 內是否有數(shù)據(jù),讀進程都會立即執(zhí)行讀操作。即如果 FIFO內沒有數(shù)據(jù),則讀函數(shù)將立刻返回 0。* (2)對于寫進程。* ? 若該管道是阻塞打開,則寫操作將一直阻塞到數(shù)據(jù)可以被寫入。* ? 若該管道是非阻塞打開而不能寫入全部數(shù)據(jù),則讀操作進行部分寫入或者調用失敗* * 函數(shù)原型 int mkfifo(const char *filename,mode_t mode)* 函數(shù)傳入值 filename:要創(chuàng)建的管道名字(包含路徑)* 函數(shù)傳入值 mode:* ? O_RDONLY:讀管道* ? O_WRONLY:寫管道* ? O_RDWR:讀寫管道* ? O_NONBLOCK:非阻塞* ? O_CREAT:如果該文件不存在,那么就創(chuàng)建一個新的文件,并用第三個參數(shù)為其設置權限* ? O_EXCL:如果使用 O_CREAT 時文件存在,那么可返回錯誤消息。這一參數(shù)可測試文件是否存在* 函數(shù)返回值:* ? 0:成功* ? EACCESS:參數(shù) filename 所指定的目錄路徑無可執(zhí)行的權限* ? EEXIST:參數(shù) filename 所指定的文件已存在* ? ENAMETOOLONG:參數(shù) filename 的路徑名稱太長* ? ENOENT:參數(shù) filename 包含的目錄不存在* ? ENOSPC:文件系統(tǒng)的剩余空間不足* ? ENOTDIR:參數(shù) filename 路徑中的目錄存在但卻非真正的目錄* ? EROFS:參數(shù) filename 指定的文件存在于只讀文件系統(tǒng)內*/ #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h>#define MYFIFO "myfifo" /* 有名管道文件名*/#define MAX_BUFFER_SIZE PIPE_BUF /* 4096 定義在于 limits.h 中*/void fifo_read(void) {char buff[MAX_BUFFER_SIZE];int fd;int nread;printf("***************** read fifo ************************\n");/* 判斷有名管道是否已存在,若尚未創(chuàng)建,則以相應的權限創(chuàng)建*/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);}memset(buff, 0, sizeof(buff));if ((nread = read(fd, buff, MAX_BUFFER_SIZE)) > 0){printf("Read '%s' from FIFO\n", buff);}printf("***************** close fifo ************************\n");close(fd);exit(0); }void write_fifo(void) {int fd;char buff[] = "this is a fifo test demo";int nwrite;sleep(2); //等待子進程先運行/* 以只寫阻塞方式打開 FIFO 管道 */fd = open(MYFIFO, O_WRONLY | O_CREAT, 0644);if (fd == -1){printf("Open fifo file error\n");exit(1);}printf("Write '%s' to FIFO\n", buff);/*向管道中寫入字符串*/nwrite = write(fd, buff, MAX_BUFFER_SIZE);if(wait(NULL)) //等待子進程退出{close(fd);exit(0);}}int main() {pid_t result;/*調用 fork()函數(shù)*/result = fork();/*通過 result 的值來判斷 fork()函數(shù)的返回情況,首先進行出錯處理*/if(result == -1){printf("Fork error\n");}else if (result == 0) /*返回值為 0 代表子進程*/{fifo_read();}else /*返回值大于 0 代表父進程*/{write_fifo();}return result; }參考資料:
總結
- 上一篇: 买车的时候应该重点关注车子的哪些方面?
- 下一篇: I.MX6ULL镜像文件