第09章IO编程.ppt

上传人:qwe****56 文档编号:70023474 上传时间:2023-01-14 格式:PPT 页数:46 大小:312.50KB
返回 下载 相关 举报
第09章IO编程.ppt_第1页
第1页 / 共46页
第09章IO编程.ppt_第2页
第2页 / 共46页
点击查看更多>>
资源描述

《第09章IO编程.ppt》由会员分享,可在线阅读,更多相关《第09章IO编程.ppt(46页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、第9章 I/O编程知识点:5个I/O模型的比较与区别常用I/O相关函数功能高级I/O函数功能Ioctl函数的6个使用方面由此需要这样的能力:如果一个或多个I/O条件满足(如输入已准备好被读,或描述字可以承接更多的输出)时,就被通知到。这个能力被称为I/O复用,是由函数select和poll支持的,对于I/O复用典型的应用如下:(1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。(2)当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。(3)如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。(4)如果一个服务器即要处理

2、TCP,又要处理UDP,一般要使用I/O复用。(5)如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。I/O模型/O模型提供了一种机制,一个或多个I/O条件满足时就被通知是哪种模型。将一个输入操作分为两个不同的阶段:(1)等待数据准备好。(2)从内核到进程拷贝数据。根据在这两个阶段的不同表现,I/O模型分为5种不同的类型,即阻塞I/O、非阻塞I/O、I/O复用、信号驱动I/O和异步I/O。1阻塞阻塞I/O模型模型以前的例子都使用了这个模型,如图所示。为了便于理解模型,考虑UDP数据报,因为UDP数据报比TCP数据报要简单一些,并且把recvfrom视为系统调用。2非阻塞非阻塞I/O

3、当请求的I/O操作非得让进程睡眠后才能进行,否则该操作不能完成,此时系统不让进程睡眠,而返回一个错误信息,直到数据报准备好,将拷贝到应用缓冲区,recvfrom返回成功指示,如图所示。3I/O复用复用I/O复用调用select或poll,并在该函数上阻塞,等待数据报套接口可读;当select返回可读条件时,调用recvfrom将数据报拷贝到应用程序缓冲区中,如图所示。4信号驱动信号驱动I/O让内核在描述字准备好时用信号SIGIO通知,通过系统调用安装一个信号处理程序,系统调用立即返回,进程继续工作,如图所示。5异步异步I/O这种模型没有被广泛应用,只作了解,如图所示。各种模型的比较select

4、函数elect函数,它允许进程指示内核等待多个事件中的任意一个发生,并仅在一个或多个事件发生或经过指定的时间时才唤醒进程。这个函数的形式如下:#include#includeint select(int maxfdp 1,fd_set*readset,fd_set*writeset,fd_set*execepset,const struct timeval*timeout);返回:准备好描述字的正数目,0为超时,-1为出错。在上面的参数中可以看到一个timeval结构,这个结构可以提供秒数和毫秒数成员,形式如下:struct timevallong tv_sec;/second*/long t

5、v_usec;/*microsecond*/这个timeval结构有以下3种可能:(1)永远等待下去:仅在有一个描述字准备好I/O时才返回,因此可以将参数timeout设置为空指针。(2)等待固定时间:在有一个描述字准备好I/O时返回,但不超过由timeout参数所指timeval结构中指定的秒数和微秒数。(3)根本不用等待:检查描述字后立即返回,这称为轮询(polling)。参数readset、writeset和execeptset指定让内核测试读、写、异常条件的描述字。如果我们对它们不感兴趣,可将其设为空指针。select函数使用描述字集为参数readset(writeset或except

6、set)指定多个描述字,描述字集是一个整数数组,每个数中的每一个对应于一个描述字,例如32位整数,则数组的第一个元素对应于031描述字,第二个元素对应于3263描述字等操作这些描述字的几个宏:voidFD_ZERO()fd_set*fdset);/*将所有位设为0*/voidFD_SET(int fd,fd_set*fdset);/*将fd位设为1*/voidFD_CLR(int fd,fd_set*fdset);/*将fd位设为0*/intFD_ISSET(int fd,fd_set*fdset):/*检测fd位是否为1*/参数readset、writeset、exceptset为值结果参数

7、,调用select时,指定我们所关心的描述字,返回时结果指示那些描述字已准备好。参数maxfdp1指定被测试的描述字的个数,它是被测试的最大描述字加1。如要测试1,2,4描述字,则必须测试0,1,2,3,4共5个描述字。函数的返回值表示所有描述字集中已准备好的描述字个数。如定时到,则返回0;若出错,则返回-1。当select()函数调用阻塞时,当套接口读、写准备好或异常时select返回,那么什么时候认为套接口准备好呢?1套接口准备好读的条件2下列3个条件中的任一个满足时,套接口准备好写3异常处理shutdown函数以前终止连接的方法是调用close函数,该函数并不进行真正的四分组终止序列,而

8、是将描述字的访问计数减1,仅在此计数为0时才关闭套接口,发送TCP的正常连接终止序列。本节介绍的函数shutdown()可避免close的两个限制:1)close将描述字的访问计数减1,仅在此计数为0时才关闭套接口。用shutdown可以激发TCP的正常连接终止序列,而不管访问计数。(2)close终止了数据传送的两个方向:读和写。由于TCP连接是全双工的,有很多时候要通知另一端已完成了数据发送,即使那一端仍有许多数据要发送也是如此。shutdown函数可以仅仅关闭连接的读、写或两个方向都关闭。如图9-7所示就是该情况下的典型函数调用。#include int shutdown(int soc

9、kfd,int howto);返回:0表示成功,-1表示出错。参数sockfd为要关闭的套接口描述字。参数howto可以为以下常值:1)SHUT_RD:关闭连接的读这一半,不再接收套接口中的数据,而且留在套接口接收缓冲区中的数据都作废。进程不能再对套接口执行任何读函数。调用此函数后,TCP套接口接收的任何数据都被确认,但数据本身扔掉。(2)SHUT_WD:关闭连接的写这一半,在TCP场合下,这种情况称为半关闭(half-close)(TCPvl的18.5节)。当前留在套接口发送缓冲区中的数据都被发送,后跟正常的TCP连接终止序列,进程不能再执行对套接口的任何写函数。(3)SHUT_RDWR:连

10、接的读这一半和写这一半都关闭,等同于调用函数shutdown()两次,第一次调用时用SHUT_RD,第二次调用时用SHUT_WR。poll函数poll()函数提供了与select()函数相似的功能,但是当涉及到流设备时,它还提供一些附加的功能。现在看一下poll函数的形式:#include int poll(struct pollfd*fdarray,unsigned long nfds,int timeout);返回:准备好描述字的个数,若为0,表示超时,若为-1,表示出错。poll函数的返回值成功时为准备好描述字的个数;出错返回-1;若定时器到,还没有描述字准备好,则返回0。如果我们不关心

11、某个描述字,可将其pollfd结构中的fd成员设为负数。第一个参数是指向一个结构数组第一个元素的指针,每个数组元素都是一个pollfd结构,它规定了为测试给定描述字fd的一些条件。下面就是pollfd结构的源代码:struct pollfd int fd;short events;short revent;要测试的条件由成员events规定,函数在相应的revents成员中返回描述字的状态(每个描述字有两个变量:一个为调用值,另一个为结果,以此避免使用值结果参数。回想一下,函数select的中间3个参数都是值结果参数)。这两个成员中的每一个都由指定某个条件的一位或多位组成。对于TCP和UDP套

12、接口,将引起poll返回的revents具体化:(1)所有正规TCP数据和UDP数据都被认为是普通数据。(2)TCP的带外数据被认为是优先级带数据。(3)当TCP连接的读这一半关闭时(如接收了一个FIN),也认为是普通数据,且后续的读操作将返回0。TCP连接存在错误既可认为是普通数据,也可认为是POLLERR错误。无论哪种情况,后续的读操作将返回-1,并设置error,这就处理了诸如接收到RST或超时等条件。(4)在监听套接口上新连接的可用性既可认为是普通数据,也可认为是优先级带数据,大多数实现都将其作为普通数据考虑。参数timeout同select中的timeout的功能一样,指定函数返回前

13、等待多长时间,它是一个指定应等待的毫秒数的正值。有3种情况:大于0,等待知道数目的时间;等于0,立即返回,不阻塞;INFTIM,永远等待。高级的I/O编程recv()和send(),它们可以把含有标志的第4个参数从进程传给内核;readv()和writev(),这两个函数可以指定一个缓冲区的向量以输入或输出数据;recvmsg()和sendmsg()函数,在其他I/O函数的所有功能基础上结合了新的接收和发送辅助数据的能力。recv和send函数函数send()的功能和write()相似,它在write()功能的基础上增加了3个参数,用来对套接字的写操作进行控制,函数的形式如下:#include

14、#include ssize_t recv(int sockfd,void*buff,size_t nbytes,int flags);ssize_t send(int sockfd,const void*buff,size_t nbytes,int flasg);返回:成功返回读入或写出的字节数,出错返回-1。sockfd是套接字描述符,buff是存放数据的应用缓冲区,nbytes是缓冲区的数据长度,flags是控制选项recvmsg和sendmsg函数这两个函数可通用在所有的I/O函数中,它可以代替read()、readv()、recv()和recvfrom()等,同样sendmsg()也

15、可以代替各种输出函数。#include ssize_t recvmsg(int sockfd,struct msghdr*msg,int flags);ssize_t sendmsg(int sockfd,struct msghdr*msg,int flags);返回:成功时为读入或写出的字节数,出错时为-1。这两个函数几乎包含了所有的读/写操作函数的功能,并把大部分参数包装到一个msghdr结构中。struct msghdrvoid*msg_name;/*protocol adderss*/socklen_t msg_namelen;/*size of protocol adderss*/s

16、truct iovec*msg_iov;/*scatter/gather array*/size_t sg_iovlen;/*#element in msg_iov*/void*msg_control;/*ancillary data;must be aligned for a cmsghdr structure*/socklen_t msg_controllen;/*length of ancillary data*/int msg_flags;/*flags returned by recvmsg()*/;非阻塞connect在默认状态下,套接口是阻塞方式的。这意味着当一个套接口调用不能立

17、即完成时,进程进入睡眠状态,等待操作完成。我们将可能阻塞的套接口调用分成以下4种:(1)输入操作(2)输出操作(3)接收外来的连接(4)初始化外出的连接非阻塞connect有如下用途:(1)可以在三次握手的同时做一些其他的处理。因为connect至少要花一个往返时间RTT完成。(2)可以用这种技术同时建立多个连接,这在Web浏览器中很普遍。(3)由于用select等待连接的完成,因此可以给select设置一个时间限制,从而改变connect默认的超时时间(通常为75s或更多)。非阻塞connect有一些其他需要注意的问题:(1)即使是非阻塞的,如果连接的服务器在同一台机器上,连接会立即建立。(

18、2)源自Berkeley的实现有两条与select和非阻塞I/O相关的规则:当连接建立成功时,描述字变成可写;当连接建立出错时,描述字变成既可读,又可写。ioctl函数它是网络程序(一般是服务器程序)中用于在程序启动时获得主机上所有接口的信息:接口的地址、接口是否支持广播、是否支持多播,也可以对套接字进行控制,如设置套接字的属主、是否是非阻塞的等。传统上的ioctl()函数是用于那些普遍使用,但不适合归入其他类别的任何特殊的相同接口,如终端、打印机等。#include int ioctl(int fd,request,/*void *arg*/);返回:若成功返回0,若出错返回-1。第3个参数

19、总是一个指针,但指针的类型依赖于request(请求)。可以把和网络有关的请求分为以下6类:套接口操作、文件操作、接口操作、ARP高速缓存操作、路由表操作和流系统。1、套接口操作有3种ioctl请求是明确针对套接口的。它们都要求ioctl的第3个参数是一个指向整数的指针。(1)SIOCATMARK:如果套接口的读指针当前在带外标志上,则通过第3个参数指向的整数返回一个非零值;否则返回0。Posix.1g用sockatmark代替了这种请求。(2)SIOCGPGRP:通过第3个参数指向的整数返回为接收来自这个套接口的SIGIO或SIGURG信号而设置的进程ID或进程组ID。这和fcntl的FGE

20、TOWN相同。(3)SIOCSPGRP:用第3个参数指向的整数设置进程ID,或进程组ID以接收这个套接口的SIGIO或SIGURG信号。这和fcntI的F_SETOWN相同。2、文件操作下面的3种请求都要求ioctl的第3个参数指向一个整数。(1)FIONBIO。套接口的非阻塞标志会根据ioctl的第3个参数指向的值是否为0而清除或设置。这个请求和用fcntl的F_SETFL命令设置和清除O_NONBLOCK文件状态标志效果相同。(2)FIOASYNC。这个标志根据ioctl的第3个参数指向的值是否为0决定清除或接收套接口上的异步I/O信号(SIGIO)。这个标志和用fcntl的F_SETFL

21、命令设置和清除O_AYNC文件状态标志效果相同。(3)FIONREAD。在ioctl的第3个参数指向的整数里返回套接口接收缓冲区中当前的字节数。这种功能在文件、管道和终端上都能用。3、接口配置很多处理网络接口的程序的第一步是从内核获取系统中配置的所有接口,这是通过SIOCGIFCONF请求来实现的,它使用了ifconf结构,ifconf又用了ifreq结构,这两种结构在下面的代码中给出。在调用ioctl之前分配一个缓冲区和一个ifconf结构,然后初始化后者。ioctl的第3个参数指向ifconf结构。假定内核返回两个ifreq结构,在ioctl返回时会得到两个ifreq结构的结果。注意:每个

22、ifreq结构包含一个联合体,有多个#define隐藏了这些域实际上是这个联合体的成员这一事实。对每个成员的引用都使用这样定义的名字。要注意的是有些系统在ifr_ifru联合体中增加了很多依赖于实现的成员。4、接口操作本节介绍一些可以获取或设置接口的其他特性的一些信息。而这些请求以ifreq结构为参数,或返回一个ifreq结构,其地址由ioctl的第3个参数指定。接口总是用名字来标识:le0、lo0、ppp0或其他在ifr_name成员中的任何内容。这些请求中有许多使用套接口地址结构在应用进程中指定或返回的IP地址或地址掩码。对于IPv4,这个地址或掩码包含在网际套接口地址结构的sin_add

23、r成员中。SIOCGIFADDR:在ifr_addr成员中返回单播地址。SIOCSIFADDR:用ifr_addr成员设置接口地址。这个接口的初始化函数也被调用。5、ARP操作ARP高速缓存也是由ioctl()函数操作的。这些请求使用一个arpreq结构。它是在头文件中定义的。ioctl的第3个参数必须指向这些结构之一。6、路由表操作有两种ioctl请求用来操作路由表。这两个请求要求ioctl的第3个参数必须是一个指向rtentry结构的指针,这个结构在头文件中定义。这些请求一般由route程序发出,只有超级用户才能发出这些请求。SIOCADDRT:向路由表中加一项。SIOCDELRT:从路由表中删去一项。ioctl没有办法列出路由表中的所有项。这种操作通常是带有r标志的netstat程序执行的。这个程序通过读内核的内存(/dev/kmem)获得路由表。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 其他杂项

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁