1. 程式人生 > >Linux系統程式設計-管道與檔案

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