《Linux/UNIX网络编程》-甘刚-电子教案 第09章IO编程

上传人:E**** 文档编号:89398460 上传时间:2019-05-24 格式:PPT 页数:46 大小:312.50KB
返回 下载 相关 举报
《Linux/UNIX网络编程》-甘刚-电子教案 第09章IO编程_第1页
第1页 / 共46页
《Linux/UNIX网络编程》-甘刚-电子教案 第09章IO编程_第2页
第2页 / 共46页
《Linux/UNIX网络编程》-甘刚-电子教案 第09章IO编程_第3页
第3页 / 共46页
《Linux/UNIX网络编程》-甘刚-电子教案 第09章IO编程_第4页
第4页 / 共46页
《Linux/UNIX网络编程》-甘刚-电子教案 第09章IO编程_第5页
第5页 / 共46页
点击查看更多>>
资源描述

《《Linux/UNIX网络编程》-甘刚-电子教案 第09章IO编程》由会员分享,可在线阅读,更多相关《《Linux/UNIX网络编程》-甘刚-电子教案 第09章IO编程(46页珍藏版)》请在金锄头文库上搜索。

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视

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

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

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

6、ct函数使用描述字集为参数readset(writeset或exceptset)指定多个描述字,描述字集是一个整数数组,每个数中的每一个对应于一个描述字,例如32位整数,则数组的第一个元素对应于031描述字,第二个元素对应于3263描述字等,操作这些描述字的几个宏: void FD_ZERO()fd_set * fdset); /*将所有位设为0*/ void FD_SET(int fd,fd_set*fdset); /*将fd位设为1*/ void FD_CLR(int fd,fd_set * fdset); /*将fd位设为0*/ int FD_ISSET(int fd,fd_set *

7、fdset): /*检测fd位是否为1*/,参数readset、writeset、exceptset为值结果参数,调用select时,指定我们所关心的描述字,返回时结果指示那些描述字已准备好。 参数maxfdp1指定被测试的描述字的个数,它是被测试的最大描述字加1。如要测试1,2,4描述字,则必须测试0,1,2,3,4共5个描述字。 函数的返回值表示所有描述字集中已准备好的描述字个数。如定时到,则返回0;若出错,则返回-1。,当select()函数调用阻塞时,当套接口读、写准备好或异常时select返回,那么什么时候认为套接口准备好呢? 1套接口准备好读的条件 2下列3个条件中的任一个满足时,

8、套接口准备好写 3异常处理,shutdown函数,以前终止连接的方法是调用close函数,该函数并不进行真正的四分组终止序列,而是将描述字的访问计数减1,仅在此计数为0时才关闭套接口,发送TCP的正常连接终止序列。本节介绍的函数shutdown()可避免close的两个限制:,1)close将描述字的访问计数减1,仅在此计数为0时才关闭套接口。用shutdown可以激发TCP的正常连接终止序列,而不管访问计数。 (2)close终止了数据传送的两个方向:读和写。由于TCP连接是全双工的,有很多时候要通知另一端已完成了数据发送,即使那一端仍有许多数据要发送也是如此。shutdown函数可以仅仅关

9、闭连接的读、写或两个方向都关闭。如图9-7所示就是该情况下的典型函数调用。,# include int shutdown(int sockfd, int howto); 返回:0表示成功,-1表示出错。 参数sockfd为要关闭的套接口描述字。 参数howto可以为以下常值:,1)SHUT_RD:关闭连接的读这一半,不再接收套接口中的数据,而且留在套接口接收缓冲区中的数据都作废。进程不能再对套接口执行任何读函数。调用此函数后,TCP套接口接收的任何数据都被确认,但数据本身扔掉。 (2)SHUT_WD:关闭连接的写这一半,在TCP场合下,这种情况称为半关闭(half-close)(TCPvl的1

10、8.5节)。当前留在套接口发送缓冲区中的数据都被发送,后跟正常的TCP连接终止序列,进程不能再执行对套接口的任何写函数。 (3)SHUT_RDWR:连接的读这一半和写这一半都关闭,等同于调用函数shutdown()两次,第一次调用时用SHUT_RD,第二次调用时用SHUT_WR。,poll函数,poll()函数提供了与select()函数相似的功能,但是当涉及到流设备时,它还提供一些附加的功能。 现在看一下poll函数的形式: # include int poll (struct pollfd *fdarray , unsigned long nfds, int timeout); 返回:准备

11、好描述字的个数,若为0,表示超时,若为-1,表示出错。 poll函数的返回值成功时为准备好描述字的个数;出错返回-1;若定时器到,还没有描述字准备好,则返回0。如果我们不关心某个描述字,可将其pollfd结构中的fd成员设为负数。,第一个参数是指向一个结构数组第一个元素的指针,每个数组元素都是一个pollfd结构,它规定了为测试给定描述字fd的一些条件。下面就是pollfd结构的源代码: struct pollfd int fd; short events; short revent; ;,要测试的条件由成员events规定,函数在相应的revents成员中返回描述字的状态(每个描述字有两个变

12、量:一个为调用值,另一个为结果,以此避免使用值结果参数。回想一下,函数select的中间3个参数都是值结果参数)。这两个成员中的每一个都由指定某个条件的一位或多位组成。,对于TCP和UDP套接口,将引起poll返回的revents具体化: (1)所有正规TCP数据和UDP数据都被认为是普通数据。 (2)TCP的带外数据被认为是优先级带数据。 (3)当TCP连接的读这一半关闭时(如接收了一个FIN),也认为是普通数据,且后续的读操作将返回0。TCP连接存在错误既可认为是普通数据,也可认为是POLLERR错误。无论哪种情况,后续的读操作将返回-1,并设置error,这就处理了诸如接收到RST或超时

13、等条件。 (4)在监听套接口上新连接的可用性既可认为是普通数据,也可认为是优先级带数据,大多数实现都将其作为普通数据考虑。,参数timeout同select中的timeout的功能一样,指定函数返回前等待多长时间,它是一个指定应等待的毫秒数的正值。有3种情况:大于0,等待知道数目的时间;等于0,立即返回,不阻塞;INFTIM,永远等待。,高级的I/O编程,recv()和send(),它们可以把含有标志的第4个参数从进程传给内核; readv()和writev(),这两个函数可以指定一个缓冲区的向量以输入或输出数据; recvmsg()和sendmsg()函数,在其他I/O函数的所有功能基础上结

14、合了新的接收和发送辅助数据的能力。,recv和send函数,函数send()的功能和write()相似,它在write()功能的基础上增加了3个参数,用来对套接字的写操作进行控制,函数的形式如下: # include # 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是套接字描述符,

15、buff是存放数据的应用缓冲区,nbytes是缓冲区的数据长度,flags是控制选项,recvmsg和sendmsg函数,这两个函数可通用在所有的I/O函数中,它可以代替read()、readv()、recv()和recvfrom()等,同样sendmsg()也可以代替各种输出函数。 # include ssize_t recvmsg (int sockfd , struct msghdr * msg , int flags ) ; ssize_t sendmsg (int sockfd , struct msghdr * msg , int flags) ; 返回:成功时为读入或写出的字节数

16、,出错时为-1。 这两个函数几乎包含了所有的读/写操作函数的功能,并把大部分参数包装到一个msghdr结构中。,struct msghdr void * msg_name; /*protocol adderss*/ socklen_t msg_namelen; /*size of protocol adderss*/ struct 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,

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号