Linux系統程式設計-管道與檔案
0x00
管道經常用於程序間通訊,程序間通過管道的讀端和寫端程序通訊。
我們介紹一個比較簡單的例子。
int main(int argc, char *argv[]) { int pipefd[2]; if (pipe(pipefd) == -1) ERR_EXIT("pipe error"); pid_t pid; pid = fork(); if (pid == -1) ERR_EXIT("fork error"); if (pid == 0) //子程序 { sleep(5); close(pipefd[0]); //關閉讀端 write(pipefd[1], "hello", 5); //寫端 close(pipefd[1]); exit(EXIT_SUCCESS); } close(pipefd[1]); //父程序,關閉寫端 char buf[10] = {0}; read(pipefd[0], buf, 10); //讀端 printf("buf=%s\n", buf); return 0; }
我們來看一張圖來理解這個程式。
父程序和子程序間擁有各自的檔案描述符,但是他們共同操作著同一個管道,所以可以實現程序間通訊。
在終端控制檯的執行結果:
(等待5秒後輸出)
注意read函式,是阻塞讀取管道中的內容。
0x01
如果想不阻塞讀取管道的內容,可以使用fcntl來改變檔案屬性,使檔案描述符處於阻塞模式:
控制檯將輸出:#include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <signal.h> #include <sys/time.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) int main(int argc, char *argv[]) { int pipefd[2]; if (pipe(pipefd) == -1) ERR_EXIT("pipe error"); pid_t pid; pid = fork(); if (pid == -1) ERR_EXIT("fork error"); if (pid == 0) { sleep(3); close(pipefd[0]); write(pipefd[1], "hello", 5); close(pipefd[1]); exit(EXIT_SUCCESS); } close(pipefd[1]); char buf[10] = {0}; int flags = fcntl(pipefd[0], F_GETFL); fcntl(pipefd[0], F_SETFL, flags | O_NONBLOCK); int ret = read(pipefd[0], buf, 10); if (ret == -1) ERR_EXIT("read error"); printf("buf=%s\n", buf); return 0; }
當沒有資料可讀時:
O_NONBLOCK disable:read呼叫阻塞,即程序暫停執行,一直等到有資料來到為止。
O_NONBLOCK enable:read呼叫返回-1,errno值為EAGAIN。
0x02
下午談一下檔案。列舉出檔案的基本操作:
1、int open(const char *pathname, int flags); 開啟檔案,返回檔案描述符。
2、ssize_t read(int fd, void *buf, size_t count); 從檔案的當前偏移讀取count個位元組到buf緩衝區。
3、ssize_t write(int fd, const void *buf, size_t count); 向檔案的當前偏移寫入count個位元組,這些位元組來源於buf。
4、off_t lseek(int fd, off_t offset, int whence); 用來移動檔案流的讀寫位置。
引數 whence 為下列其中一種:
SEEK_SET 從距檔案開頭offset 位移量為新的讀寫位置。
SEEK_CUR 以目前的讀寫位置往後增加offset 個位移量。
SEEK_END 將讀寫位置指向檔案尾後再增加offset 個位移量. 當whence 值為SEEK_CUR 或 SEEK_END 時, 引數offset 允許負值的出現。
5、int fcntl(int fd, int cmd, ... /* arg */ ); 用來改變檔案的屬性。
int flags = fcntl(pipefd[0], F_GETFL);
fcntl(pipefd[0], F_SETFL, flags | O_NONBLOCK);
6、int stat(const char * file_name, struct stat *buf); 用來獲取檔案狀態 。#include <sys/stat.h>
#include <unistd.h>
main()
{
struct stat buf;
stat("/etc/passwd", &buf);
printf("/etc/passwd file size = %d \n", buf.st_size);
}
參考http://c.biancheng.net/cpp/html/326.html。