⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 00000012.htm

📁 一份很好的linux入门资料
💻 HTM
字号:
<HTML><HEAD>  <TITLE>BBS水木清华站∶精华区</TITLE></HEAD><BODY><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER>发信人:&nbsp;SuperSB&nbsp;(孤鹰),&nbsp;信区:&nbsp;Linux&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>标&nbsp;&nbsp;题:&nbsp;[转载]unix环境高级编程-12&nbsp;<BR>发信站:&nbsp;BBS&nbsp;水木清华站&nbsp;(Wed&nbsp;Mar&nbsp;15&nbsp;14:30:35&nbsp;2000)&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>发信人:&nbsp;taosm&nbsp;(128+64--&gt;cool),&nbsp;信区:&nbsp;unix&nbsp;&nbsp;<BR>标&nbsp;&nbsp;题:&nbsp;unix环境高级编程--第12章&nbsp;高级I/O&nbsp;&nbsp;<BR>发信站:&nbsp;西十八BBS&nbsp;(Sat&nbsp;Mar&nbsp;11&nbsp;13:50:56&nbsp;2000),&nbsp;转信&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;<BR>第十二章&nbsp;&nbsp;&nbsp;高级I/O&nbsp;&nbsp;<BR>12.1&nbsp;引言&nbsp;&nbsp;<BR>本章内容包括:非阻塞I/O、记录锁、系统V流机制、I/O多路转接(select和poll&nbsp;&nbsp;<BR>函数)、readv和writev函数,以及存储映照I/O(mmap)。在第十四章、十五章中&nbsp;&nbsp;<BR>说明的进程间通信,以及以后各章中的很多实例都要使用本章所述的概念和函数。&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;<BR>12.2&nbsp;非阻塞I/O&nbsp;&nbsp;<BR>在10.5节中曾将系统调用分成两类:低速系统调用和其它。低速系统调用是可能会&nbsp;&nbsp;<BR>使进程永远阻塞的一类系统调用:&nbsp;&nbsp;<BR>l&nbsp;如果数据并不存在,则读文件可能会使调用者永远阻塞(例如读管道,终端设备&nbsp;&nbsp;<BR>和网络设备)。&nbsp;&nbsp;<BR>l&nbsp;如果数据不能立即被接受,则写这些同样的文件也会使调用者永远阻塞。&nbsp;&nbsp;<BR>l&nbsp;在某些条件发生之前,打开文件会被阻塞(例如打开一个终端设备可能需等待到&nbsp;&nbsp;<BR>一个连接的调制解调器应答;又例如若以只写方式打开FIFO,那么在没有其它进程&nbsp;&nbsp;<BR>已用读方式打开该FIFO时也要等待)。&nbsp;&nbsp;<BR>l&nbsp;对已经加上了强制性记录锁的文件进行读、写。&nbsp;&nbsp;<BR>l&nbsp;某些ioctl操作。&nbsp;&nbsp;<BR>l&nbsp;某些进程间通信函数(第十四章)。&nbsp;&nbsp;<BR>虽然读、写磁盘文件会使调用在短暂时间内阻塞,但并不能将它们视为&quot;低速&quot;。&nbsp;&nbsp;<BR>非阻塞I/O使我们可以调用不会永远阻塞的I/O操作,例如open,read和write。如果&nbsp;&nbsp;<BR>这种操作不能完成,则立即出错返回,表示该操作如继续执行将继续阻塞下去。&nbsp;&nbsp;<BR>对于一个给定的描述符有两种方法对其指定非阻塞I/O:&nbsp;&nbsp;<BR>1.&nbsp;如果是调用open以获得该描述符,则可指定O_NONBLOCK标志(3.3节)。&nbsp;&nbsp;<BR>2.&nbsp;对于已经打开的一个描述符,则可调用fcntl,对其打开O_NONBOCK文件状态标&nbsp;&nbsp;<BR>志(3.13节)。在程序3.5中的函数可用来为一个描述符打开任一文件状态标志。&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;<BR>早期的系统V版本使用标志O_NDELAY指定非阻塞方式。在这些版本中,如果无数据&nbsp;&nbsp;<BR>可读,则read返回值0。而Unix又常将read的返回值0解释为文件结束,两者有所混&nbsp;&nbsp;<BR>淆。PISIX.1则提供了一个非阻塞标志,它的名字和语义都与O_NDELAY不同。PISI&nbsp;&nbsp;<BR>X.1要求,对于一个非阻塞的描述符如果无数据可读,则read返回-1,并且errno被&nbsp;&nbsp;<BR>设置为EAGAIN。SVR4支持较老的O_NDELAY和POSIX.1的O_NONBLOCK,但在本书的实&nbsp;&nbsp;<BR>例中只使用POSIX.1规定的特征。O_NDELAY是为了向后兼容性,不应在新应用程序&nbsp;&nbsp;<BR>中使用。&nbsp;&nbsp;<BR>4.3BSD为fcntl提供FNDELAY标志,其语义也稍有区别。它不只影响该描述符的文件&nbsp;&nbsp;<BR>状态标志,它将终端设备或套接口的标志更改成非阻塞的,因此影响了终端或套接&nbsp;&nbsp;<BR>口的所有用户,不只是影响共享同一文件表项的用户(4.3BSD非阻塞I/O只对终端&nbsp;&nbsp;<BR>和套接口起作用)。如果对一个非阻塞描述符的操作不能无阻塞地完成,那么4.3&nbsp;&nbsp;<BR>BSD返回EWOULDBLOCK。4.3+BSD提供POSIX.1的O_NONBLOCK标志,但其语义却类似于&nbsp;&nbsp;<BR>4.3BSD的FNDELAY。非阻塞I/O通常用来处理终端设备或网络连接,而这些设备通常&nbsp;&nbsp;<BR>一次由一个进程使用。这就意味着BSD语义的更改通常不会影响我们。出错返回EW&nbsp;&nbsp;<BR>OULDBLOCK而不是POSIX.1的EAGAIN,这造成了可移植性问题,我们必须处理这一问&nbsp;&nbsp;<BR>题。4.3+BSD也支持FIFO,非阻塞I/O也对FIFO起作用。&nbsp;&nbsp;<BR>实例&nbsp;&nbsp;<BR>程序12.1是一个非阻塞I/O的实例,它从标准输入读100,000字节,并试图将它们&nbsp;&nbsp;<BR>写到标准输出上。该程序先将标准输出设置为非阻塞的,然后用for循环进行输出&nbsp;&nbsp;<BR>,每次写的结果都在标准出错上打印。函数ctl-f1类似于程序3.5中的set-f1,但&nbsp;&nbsp;<BR>与set-f1的功能相反,它清除1个或多个标志位。&nbsp;&nbsp;<BR>#include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;sys/types.h&gt;&nbsp;&nbsp;<BR>#include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;errno.h&gt;&nbsp;&nbsp;<BR>#include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;fcntl.h&gt;&nbsp;&nbsp;<BR>#include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;ourhdr.h&quot;&nbsp;&nbsp;<BR>char&nbsp;&nbsp;&nbsp;&nbsp;buf[100000];&nbsp;&nbsp;<BR>int&nbsp;&nbsp;<BR>main(void)&nbsp;&nbsp;<BR>{&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ntowrite,&nbsp;nwrite;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;&nbsp;&nbsp;&nbsp;*ptr;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ntowrite&nbsp;=&nbsp;read(STDIN_FILENO,&nbsp;buf,&nbsp;sizeof(buf));&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;&quot;read&nbsp;%d&nbsp;bytes\n&quot;,&nbsp;ntowrite);&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_fl(STDOUT_FILENO,&nbsp;O_NONBLOCK);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;set&nbsp;nonblocking&nbsp;*/&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(ptr&nbsp;=&nbsp;buf;&nbsp;ntowrite&nbsp;&gt;&nbsp;0;&nbsp;)&nbsp;{&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errno&nbsp;=&nbsp;0;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nwrite&nbsp;=&nbsp;write(STDOUT_FILENO,&nbsp;ptr,&nbsp;ntowrite);&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;&quot;nwrite&nbsp;=&nbsp;%d,&nbsp;errno&nbsp;=&nbsp;%d\n&quot;,&nbsp;nwrite,&nbsp;errno);&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(nwrite&nbsp;&gt;&nbsp;0)&nbsp;{&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ptr&nbsp;+=&nbsp;nwrite;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ntowrite&nbsp;-=&nbsp;nwrite;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clr_fl(STDOUT_FILENO,&nbsp;O_NONBLOCK);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;clear&nbsp;nonblocking&nbsp;*/&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(0);&nbsp;&nbsp;<BR>}&nbsp;&nbsp;<BR>程序12.1&nbsp;&nbsp;长的非阻塞写&nbsp;&nbsp;<BR>若标准输出是普通文件,则可以期望write只执行一次。&nbsp;&nbsp;<BR>$&nbsp;ls&nbsp;-l&nbsp;/etc/termcap&nbsp;&nbsp;<BR>&nbsp;印文件长度&nbsp;&nbsp;<BR>-rw-rw-r-1&nbsp;root&nbsp;133439&nbsp;Oct&nbsp;11&nbsp;1990&nbsp;/etc/termcap&nbsp;&nbsp;<BR>$a.out&nbsp;&lt;&nbsp;/etc/termcap&nbsp;&gt;temp.file&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;先试一普&nbsp;&nbsp;<BR>&nbsp;文件&nbsp;&nbsp;<BR>read&nbsp;100000&nbsp;bytes&nbsp;&nbsp;<BR>nwrite-100000,&nbsp;errno=0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一次写&nbsp;&nbsp;<BR>$ls&nbsp;-l&nbsp;temp.file&nbsp;&nbsp;<BR>&nbsp;验输出文件长度&nbsp;&nbsp;<BR>-rw-rw-r-1&nbsp;stevens&nbsp;100000&nbsp;Nev&nbsp;21&nbsp;16:27&nbsp;temp.file&nbsp;&nbsp;<BR>但是,若标准输出是终端,则可期望write有时会返回一个数字,有时则出错返回&nbsp;&nbsp;<BR>。下面是在一个系统上运行程序12.1的结果:&nbsp;&nbsp;<BR>$&nbsp;a.out&nbsp;&lt;&nbsp;/etc/termcap&nbsp;2&gt;stderr.out&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;向终端输出&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大量输出至终端&nbsp;&nbsp;<BR>$&nbsp;cat&nbsp;stderr.out&nbsp;&nbsp;<BR>read&nbsp;100000&nbsp;bytes&nbsp;&nbsp;<BR>nwrite=8192,&nbsp;errno=0&nbsp;&nbsp;<BR>nwrite=8192,&nbsp;errno=0&nbsp;&nbsp;<BR>nwrite=-1,&nbsp;errno=11&nbsp;&nbsp;<BR>庵执

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -