循序漸進學unix——上機記錄(三)


連考了兩週試,好久不見……

這次上機主題是“pipe”,內容比較多,我分兩次記錄。

  • 簡單的重定向
使用fork創建一個子進程,並把它的標準輸出重定向到一個名爲sortie的文件。需要掌握的命令/函數有open,close,dup,dup2。
在unix中,一切皆文件。當我們用open函數打開一個普通文件時,函數會返回一個fd(file descriptor)作爲這個文件的標識。同樣,系統的其他一些設備也被當作文件,從而有各自的標識符。比如0默認表示標準輸入,即鍵盤。這時鍵盤被當作一個只讀的文件。1表示標準輸出,2表示標準錯誤輸出,這兩個標識符都默認指向屏幕。這道題的要求是把標準輸出,也就是fd=1,重定向到一個文件。

爲此,我們首先用close命令把fd=1釋放,也就是切斷了它到標準輸出的聯繫。之後使用dup把文件sortie的fd的指向,複製到fd=1的位置,此時已完成重定向,我們使用close把複製前的fd關掉即可。dup函數把參數中傳入的fd複製到最小的,未被佔用的fd位置,即我們剛剛關掉的1. 具體的命令描述請使用man命令。

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void main(int argc, char** argv)
{

	if(fork()==0) {
		//Section fils
		int fp = open("sortie", O_CREAT | O_WRONLY );
		if(fp == -1) {
			perror(0);
			exit(0);
		}
		printf("Avant la redirection\n");
		dup2(fp, 1);
		close(fp);
		printf("Après la redirection\n");
		execlp("echo", "echo", "I want to appear in the stdout, but...", NULL);
		exit(0);
	} else {
		//pere
	}
}



  • 創建子進程並與父進程使用pipe進行簡單的通信。
pipe通信是同步的,也就是說當一個進程使用read試圖從pipe中讀取數據時,如果此時pipe中沒有數據,則此進程會被卡在這裏,等待寫入的數據。這一行爲可以通過設置標誌位更改,我們以後討論。
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void main(int argc, char** argv)
{
	char a = 'a';
	char b = 'b';
	char rcv;
	int tube[2];
	pipe(tube);
	if(fork()==0) {
		//Section fils
		printf("Fils : write 'a' au tube.\n");
		write(tube[1], &a, 1);
		printf("Fils : Sleep 5 secondes avant l'écriture.\n");
		sleep(5);
		printf("Fils : write 'b' au tube.\n");
		write(tube[1], &b, 1);
		exit(0);
	} else {
		//pere
		read( tube[0], &rcv, 1);
		printf("Père : read du tube :%c. Lire le char suivant.\n", rcv);
		read( tube[0], &rcv, 1);
		printf("Père : read du tube :%c. \n", rcv);
	}
}



  • 創建兩個子進程A和B。將A的標準輸出重定向到一個pipe的輸入端,將B的標準輸入定向到pipe的輸出端。兩個進程通過pipe進行通信。
提醒一下,pipe也是文件。只不過可以由多個進程同時進行讀寫。
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void main(int argc, char** argv)
{
	char a = 'a';
	char b = 'b';
	char rcv;
	int tube[2];
	pipe(tube);
	if(fork()==0) {
		//Section fils
		dup2(tube[1], 1);
		close(tube[1]);
		printf("a");
		//write(tube[1], &a, 1);
		exit(0);
	} else {
		//pere
		dup2(tube[0], 0);
		close(tube[0]);
		
		read( 0, &rcv, 1);
		//printf("Père : read du tube :%c. Lire le char suivant.\n", rcv);
		//read( tube[0], &rcv, 1);
		printf("Père : read du tube :%c. \n", rcv);
	}
}


  • 讓我們再亂一些。雙重重定向,兩個pipe。兩個子進程AB。將A的標準輸出重定向到pipe1的輸入端,標準輸入定向到pipe2的輸出端。將B的標準輸出重定向到pipe2的輸入端,標準輸入定向到pipe1的輸出端。兩個進程通過pipe進行通信。
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void main(int argc, char** argv)
{
	char a = 'a';
	char b = 'b';
	char rcv;
	FILE* fd;
	int tube[2];
	int tube2[2];
	pipe(tube);
	pipe(tube2);
	if(fork()==0) {
		//Section fils
		dup2(tube[1], 1);
		dup2(tube2[0], 0);
		close(tube[1]);
		close(tube2[0]);

		printf("a");
		fflush(stdout);
		//read(0, &rcv, 1);
		scanf("%c",&rcv);
		fprintf(fdopen(2, "w"), "filsfilsbbb\n");
		//fd = fopen("fils.txt", "w");
		//fd = fopen("fils.txt", O_CREAT | O_WRONLY);
		//fprintf(fd, "Fils : receive b\n");	
//write(tube[1], &a, 1);
		exit(0);
	} else {
		//pere
		dup2(tube[0], 0);
		dup2(tube2[1], 1);
		close(tube[0]);
		close(tube2[1]);
		
		//read( 0, &rcv, 1);
		scanf("%c", &rcv);
		fprintf(stderr, "perepereaaa\n");
		//fd = fopen("pere.txt", O_CREAT | O_WRONLY);
//		fd = fopen("pere.txt", "w");
//		fprintf(fd, "receive a\n");
		printf("b");	
		//printf("Père : read du tube :%c. Lire le char suivant.\n", rcv);
		//read( tube[0], &rcv, 1);
		//printf("Père : read du tube :%c. \n", rcv);
	}
}

哦了,先貼到這,後半部分晚些時候再上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章