您的位置:首页 > 运维架构 > Linux

【Unix/Linux编程实践】理解I/0重定向和管道

2015-12-13 11:01 525 查看

一.3个标准文件描述符

0:stdin

1:stdout

2:stderr

通过shell命令行运行Unix系统工具时,stdin,stdout,stderr连接在终端上,因此,工具从键盘读取数据,并把输出和错误消息写到屏幕。

二.重定向I/O的是shell而不是程序

shell并不把重定向标记和文件名传递给程序;

重定向可以出现在命令行中的任何地方,且重定向标识符周围并不需要空格来区分。

*最低可用文件描述符原则:当打开文件时,为此文件安排的描述符总是此数组中最低可用位置的索引。

三.如何将stdin定向到文件

1.close then open:

首先close(0),切断标准输入与终端设备的连接,于是描述符0处于空闲状态。

接下来open(filename, O_RDONLY)打开一个想连接到stdin上去的文件,由于当前最低可用文件描述符是0,因此打开的文件被连接到stdin上,于是任何从stdin读取数据的函数都将从此文件读入。

2.open-close-dup-close

首先open(file)打开想要重定向到的文件,这时返回一个文件描述符,当并不是0,因为0已经连到终端了。

然后close(0),使得0描述符空闲。

通过dup(fd)将文件描述符做了一个复制,复制使用最低可用文件描述符,于是获得0号描述符。

最后close(fd)断开文件的原始连接。

(可以使用dup2(fd, 0)来替代close(0), dup(fd))

相似的例子:

电话响了,我拿起本楼层的分机,但是电话是找我爸爸的,我爸在一楼,于是我会让我爸接起一楼的分机,这是有了两个连接,接下来我把电话挂断,此时就只剩下楼下分机的连接了!

四.如何为其他程序重定向I/O

例子: who > userlist

思想:shell使用进程通过fork产生子进程与子进程调用exec之间的时间间隔来重定向标准输入输出到文件。

过程:

1.进程的文件描述符1连接在打开的文件f上。

2.父进程调用fork,子进程继承父进程的代码,数据,打开文件的文件描述符。此时描述符1依然指向文件f。

3.子进程调用close(1),并尝试打开文件g,则文件描述符1被连接到文件g中,子进程的标准输出被重定向到g。

4.子进程调用exec来执行who,此时子进程的代码和数据都被who程序的代码和数据替代,但是【文件描述符被保留下来了】。

(打开的文件属于进程的属性,就像调用exec之后进程的pid不会改变一样。)

之后who命令将数据传送至文件描述符1,事实上被写到了文件g中,而who命令对此毫不知晓。

五.管道

管道是内核中的一个单向的数据通道,它有一个读取端和一个写入端。

我们调用pipe(int array[2])来创建管道并将其两端连接到两个文件描述符,array[0]为读取端的文件描述符。pipe调用也使用最低可用文件描述符。

使用fork来共享管道

当进程调用fork时,子进程也得到了父进程的管道连接,父进程和子进程都可以读写管道的数据。当一个进程读,一个进程写时,效率将十分高!

一些细节

1.管道读取阻塞:进程视图从管道读数据时,进程被挂起直到数据被写进管道。

2.读取结束标志:当所有写着关闭了管道的写数据端时。

3.管道是一个队列:当进程从管道读取数据后,数据就不存在了,如果有多个读者,则读取的数据将是不完整的。

4.写入数据阻塞直到管道有空间去容纳新的数据:比如有1000个字节要写,但是管道只能容纳500个字节,那么进程将会被挂起直到有足够空间。

5.写入必须保证一个最小的块大小:POSIX标准规定内核不会拆分小于512字节的块。而Linux则保证管道中可以存在4096字节的连续缓存。如果两个进程向管道写数据,并且每一个进程都限制其消息不大于512字节,那么这些消息都不会被内核拆分。

(此处不太理解T~T)

6.若无读者在读数据,则写操作执行失败:如果所以的读操作都已将管道的读取端关闭,那么对管道的写入调用将会执行失败。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: