- 论坛徽章:
- 0
|
***继续,修复了先前版本翻译不是很妥的地方,不知道代码怎么插入,帮忙整理整理格式,多谢***
本章示范(示例)代码:http://www.khmere.com/freebsd_book/src/05/index.html
5.1 基本输入输出
一般来说,Unix信奉简单设计的哲理。"一切都是文件"是个很强大的特征--这就意味着你所编辑的文本文件具有和调制解调器、打印机或网卡相同的编程接口,就像编辑文本文件一样,你应该能够对它们(被编辑文件)执行基本的读、写操作等等。尽管这个想法现行的实现不完美,BSD Unix实际上做到非常接近了,这也正是BSD又一个强大的地方--简洁而优雅。有些不是真实的文件而是设备,它们的入口在/dev目录下,有些设备只能用于特殊的操作,如块的读、写,一个极端的例子是以太网设备,甚至它(以太网设备)在FreeBSD 5之前在/dev下面没有入口。
操作系统看待每件事都像文件,一个好的示范是Plan 9,Plan 9用文件实现一切,甚至以太网和网络协议;更详细的信息可以参考Plan 9的主页http://www.cs.bell-labs.com/plan9dist/
一般来说,文件是计算机上数据最基本、最初级的表现形式,本质上是数据一位一位的线性序列。当用exec命令执行编译过的程序时,系统将把二进制文件读入内存,代码将在分配到内存地址空间后被执行,程序被定位在什么位置跟exec命令有关,它可以在软磁盘,硬盘,光驱,甚至是加载的另一半还分布在世界其他角落的网络文件系统上;跟基于网络链路发送数据一样,内容被顺序地一位一位地读入。当一个程序发送数据的时候,数据本身是一位一位的线性序列,有些时候叫做“流”,程序不关心它是否基于网络链路发送数据,它仅仅写数据;这两种最基本的操作,读跟写,是计算鸡用到的最多的。
本章将涉及最基本的I/O子系统跟进程资源。
5.2 基本输入输出
UNIX进程打开文件的时候,会保存文件描述符的参考值,该值是一个整数,不论何时在UNIX系统上创建一个进程,都会给它3个文件描述符:
0 标准输入
1 标准输出
2 标准错误
这些值能够用于描述终端、文件的读写,甚至设置其他进程的描述。使shell重定向, cat /etc/hosts >> hosts.out, shell将打开文件hosts.out并且将cat /etc/hosts做为自己的参数执行。不管怎样,当cat进程写到标准输出后(1),结果不会被tty得到,而是输出到hosts.out文件。(cat程序根本不知道写入了文件系统的文件,还是写入到标准输出的文件描述符,我们将在这章的后面一点看到究竟是怎么实现的)
最基本的两个操作描述符是Open和Close函数
Open函数
- int open(const char *path, int flags, /* mode */ );,
复制代码
成功地调用这个函数后,Open函数将返回文件及参数的描述符,这个整型描述符在进程文件描述表内生成索引。该描述符的结构能够让内核知道如何操作这个文件。在BSD上,这个结构叫做filedesc,并且能够在/usr/include/sys/filedesc.h这个头文件中找到。当进程要在这个描述符上执行一些操作的时候,它将要求文件描述符为读、写、可执行操作指定一个整数值。
内核保存了所有文件描述符的基准值,这些基准值将在时进程打开、复制它或者已经处于打开状态的文件描述符执行exec调用、跨越fork的过程中增加。当这个参考值为0的时候,文件关闭。意思是,如果你有一个程序执行fork或者exec调用,并且close-on-exec位没有指定,基准值将增加;并且当一个新的程序执行了fork或者exec调用,基准值将继续增加。所以文件一直处于打开状态,直到基准值被设置为0,或者直到所有的进程关闭它,或者退出。
Close函数
当进程想移除或者关闭一个打开的文件描述符的时候,它将调用close函数。这将关闭指定的文件描述符,并且减少文件描述符的参考值。这个过程很像 exit————当一个进程执行exit,所有打开的文件描述符跟进程一起被自动地减少,自从文件参考值设为0,内核将释放所有的文件入口的副本.
getdtablesize函数
getdtablesize函数返回文件描述表的大小,它能用作检查系统限制,你也能够用下面的命令做相同的事情。
- bash$ sysctl kern.maxfilesperproc
- kern.maxfilesperproc: 3722
复制代码
依赖于你的系统,你能够在系统运行的时候调整它,或者从新编译你的内核,这个函数不能检查当前进程打开了多少文件,(跟getdtablesize一样)仅仅返回你的进程能够打开文件的最大个数。
fcntl函数
- int fcntl(int fd, int cmd, ...);
复制代码
fcntl函数允许进程操作文件描述符,fcntl函数至少需要指定两个参数,一个有效的文件描述符,一个命令。根据使用的命令,决定fnctl是否需要第三个参数,下面为命令定参数义了一些值。在FreeBSD上,你能在/usr/include/fcntl.h头文件中找到它们。
F_DUPFD用作创建一个新的很像原型的文件描述符,(你能够用dup调用做到相同的事情,将在晚些时候涉及到),当成功执行带F_DUPFD标记的fcntl函数,fcntl将返回下面属性之一的新的文件描述符:
- 假如指定了第三个参数,描述符返回的值比最小可用的描述符,该值等于或者比给定的第三个参数的值大一点,返回的描述符将参照指定给fcntl第一个参数的文件描述符
- 假如fcntl指定的文件描述符是一个文件,新文件描述符将有相同的文件偏移量,并且新文件描述符将有相同的访问方式(如:O_RDONLY,O_RDWR,o_WRONLY)
- 新文件描述符将共享文件状态标记
- 新文件的“close-on-exec”标志将被关闭,即新的文件描述符在exec调用之后仍将保持打开。
F_GETFD命令
F_GETFD命令用作获取"close-on-exec"标记的状态,跟FD_CLOSEXEC相与后返回值要么为0,要么为1。如果返回0,close-on-exec标记没有被设置过,那么文件描述符将保持调用交叉执行调用(so the file descriptor will remain open across exec calls.),假如是1,close-on-exec标志被设置过,文件描述符将在成功调用一个exec函数后被关闭。
F_SETFD命令
F_SETFD命令用作设置文件描述符的close-on-exec标志位。第三个参数要么是FD_CLOEXEC,设置close-on-exec标记,要么是0,取消close-on-exec标记的设置。
F_GETFL和F_SETFL命令
- #define F_GETFL 3
- #define F_SETFL 4
复制代码
F_GETFL命令将使fcntl返回当前文件描述符状态标记,当返回值加上O_ACCMODE(#define O_ACCMODE 0x0003)能够获取到打开的方式,F_SETFL命令将根据第三个参数设置文件状态标记。
公共的标记
下面这些标记也用作调用open,并且只能被跟上期望的标记调用open函数设置,这是最常见的,检查你系统的头文件能够查到那些值
如果O_RDONLY标记被设置,那么文件只能以只读方式打开。注意这个O_RDONLY标记只能在打开的时候被设置,它不能被fnctl加F_SETFL命令设置。
如果O_WRONLY标记被设置,那么文件只能以只写方式打开。这个标记只能被open设置,不能被fcntl加F_SETFL命令设置。
如果O_RDWR标记被设置,那么文件以可读可写方式打开。这个标记也只能被open调用设置。
- #define O_NONBLOCK 0x0004
复制代码
如果O_NONBLOCK标记被设置,文件描述符将不被阻塞而被直接返回替代。一个例子是打开tty。如果用户不在终端调用里输入任何东西,read将被阻塞,直到用户有输入,当O_NONBLOCK标记被设置,read调用将直接返回设置到EAGAIN的值
如果O_APPEND标记被设置,文件将以追加方式打开,并且将从文件末尾开始写入。
如果O_SHLOCK标记被设置,文件描述符将在文件上生成一个共享锁,在文件上设置了共享锁,多个进程能在同一个文件够执行操作,文件共享锁的详细信息,可用看fnctl函数的F_GETLK跟F_SETL命令。
如果O_EXLOCK标记被设置,文件描述符将在文件上生成一个可执行锁,一样,更详细的描述可以参照fcntl函数的F_SETLK跟F_GETLK命令。
如果O_ASYNC标记被设置,进程集将被发送的SIGIO信号通知,在文件描述符号的IO是可用的。详细的描述请参照信号那一章。
如果O_FSYNC标记被设置,所有写到文件描述符的写操作将不被内核缓存,取而代之的是将被写到介质,并且所有的写调用都将被阻塞,直到内核完成(写操作)。
- #define O_NOFOLLOW 0x0100
复制代码
如果O_NOFOLLOW标记被设置,假如文件是一个符号连接,open调用将会失败。如果在一个有效的文件描述符上设置了这个标志,那么当前文件就不是一个符号连接。
如果O_CREAT标记被设置,假如执行open调用的时候文件不存在,那么文件可用被创建。(这个错误的拼写很有趣;when one of the original creators of C was asked "What one thing would you change about C?" he replied, "I would change O_CREAT to O_CREATE!", or at least how the rumor goes)
如果O_TRUNC标记被设置,成功地调用open后文件将被截除。
当O_EXCL标记被设置,假如文件已经存在,open调用将产生一个错误。
F_GETOWN命令用于描述符获取当前进程或者进程集收到的SIGIO信号。如果这个值是一个正数,它表示一个进程,负数表示一个进程集。
当IO就绪的时候,F_SETOWN命令用作设置进程或者进程集使其接收SIGIO信号,指定一个进程,用一个正数(一个进程ID)作为fcntl的第三个参数,否则,用一个负数作为fcntl的第三个参数指定进程集。
[ 本帖最后由 雨丝风片 于 2006-2-18 16:08 编辑 ] |
|