2012年12月21日

来源:互联网 发布:网络英语教程 编辑:程序博客网 时间:2024/06/05 21:58


“Unix 中所有的东西就是文件!”那个家伙也许正在说到一个事实:Unix 程序在执行任何形式的 I/O 的时候,程序是在读或者写一个文件描述符。一个文件描述符只是一个和打开的文件相关联的整数。但是(注意后面的话),这个文件可能是一个网络连接,FIFO,管道,终端,磁盘上的文件 或者什么其他的东西。Unix中所有的东西是文件!因此,你想和 Internet 上别 的程序通讯的时候,你将要通过文件描述符。最好相信刚才的话。
现在你脑海中或许冒出这样的念头:“那么我从哪里得到网络通讯的文件描述符呢,聪明 人?”无论如何,我要回答这个问题:你利用系统调用socket()。他返回套接口描 述符 (socket descriptor),然后你再通过他来调用 send() 和recv()。
“但是...”,你可能现在叫起来,“如果他是个文件描述符,那么为什么不用一般的调用 read() 和 write()来通过套接口通讯?”简单的答案是:“你可以使用 一般的函数!”。详细的答案是:“你可以,但是使用 send() 和 recv()让你更好的控制数据传输。”

 

 对于文件描述符的初识。APUE中是这样介绍文件描述符的(APUE p59):对于内核而言,所有打开的文件都通过文件描述符引用,文件描述符是一个非负整数,当打开一个现有或创建一个新的文件的时候,内核回想进程返回一个文件描述符,当读或者写一个文件时,使用open或creat返回的文件描述符标识该文件,将其作为参数传递给read或write。


     posix中,定义文件描述符0,1,2分别为:STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO.这些定义在<unistd.h>中。

     关于文件描述符的优缺点:(来自维基百科)

     优点:
  •        基于文件描述符的I/O操作兼容POSIX标准。
  •        在UNIX、Linux的系统调用中,大量的系统调用都是依赖于文件描述符。

      缺点:

  •        在非UNIX/Linux操作系统上(如Windows NT),无法基于这一概念进行编程。
  •        由于文件描述符在形式上不过是个整数,当代码量增大时,会使编程者难以分清哪些整数意味着数据,那些意味着文件描述符。
由于posix中定义的宏占用了0,1,2这三个文件描述符,所以,当调用能过返回文件描述符的系统调用时一般都是从3开始进行分配。


以上只是对文件描述符的简单认识,其实一直很郁闷的是文件描述符只是一个int型的整数,如何通过它来对存在磁盘上的文件进行操作。通过进一步了解发现,其实在每个进程中都维护着一张文件描述符表,这张表中的文件描述符对应着一个文件指针,可以找到这个文件描述符所对应的文件,如果没有分配的文件描述符其所对应的指针为NULL。而文件指针中的inode成员便记录了该文件所对应的inode节点。

而很多系统调用都是通过对这个文件指针的操作来进行的。

|--------|------------|               |--------------------|
|   fd   |文件指针 |-------------> | 文件状态标志  |
|--------|------------|                |--------------------|                    
|--------|------------|                |当前文件偏移量 |
|   ...   |   ....                     |--------------------|
|--------|------------|                |inode节点指针 |--------------------------->|-----------------------------|
                                       |--------------------|                              | inode节点信息          |
                                                                                           |----------------------------|

当某个程序打开文件时,操作系统返回相应的文件描述符,程序为了处理该文件必须引用此描述符。所谓的文件描述符是一个低级的正整数。最前面的三个文件描述符(0,1,2)分别与标准输入(stdin),标准输出(stdout)和标准错误(stderr)对应。因此,函数scanf() 使用 stdin,而函数 printf() 使用 stdout。你可以用不同的文件描述符改写默认的设置并重定向进程的I/O 到不同的文件。

1、首先说什么是文件描述符,它有什么作用?
文件描述符是一个简单的整数,用以标明每一个被进程所打开的文件和socket。第一个打开的文件是0,第二个是1,依此类推。
  
文件描述符
是个很小的正整数,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。 
  文件描述符的优点:兼容POSIX标准,许多
Linux

UNIX
系统调用都依赖于它。
  文件描述符的缺点:不能移植到UNIX以外的系统上去,也不直观。
   基于文件描述符的输入输出函数:
  open:打开一个文件,并指定访问该文件的方式,调用成功后返回一个文件描述符。
  creat:打开一个文件,如果该文件不存在,则创建它,调用成功后返回一个文件描述符。
  close:关闭文件,进程对文件所加的锁全都被释放。
  read:从文件描述符对应的文件中读取数据,调用成功后返回读出的字节数。
  write:向文件描述符对应的文件中写入数据,调用成功后返回写入的字节数。
  ftruncate:把文件描述符对应的文件缩短到指定的长度,调用成功后返回0。
  lseek:在文件描述符对应的文件里把文件指针设定到指定的位置,调用成功后返回新指针的位置。
  fsync:将所有已写入文件中的数据真正写到磁盘或其他下层设备上,调用成功后返回0。
  fstat:返回文件描述符对应的文件的相关信息,把结果保存在structstat中,调用成功后返回0。
  fchown:改变与打开文件相关联的所有者和所有组,调用成功后返回0。
  fchmod:把文件描述符对应的文件的权限位改为指定的八进制模式,调用成功后返回0。
  flock:用于向文件描述符对应的文件施加建议性锁,调用成功后返回0。
  fcntl:既能施加建议性锁也能施加强制性锁,能建立记录锁、读取锁和写入锁,调用成功后返回0。
  dup:复制文件描述符,返回没使用的文件描述符中最小的编号。
  dup2:由用户指定返回的文件描述符的值,用来重新打开或重定向一个文件描述符。
  select:同时从多个文件描述符读取数据或向多个文件描述符写入数