日期:2014-05-16  浏览次数:20757 次

循序渐进学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"