网络编程7-多路复用.ppt
网络编程多路复用,郑秋华,大纲,多线程作业讲解阻塞、非阻塞、异步和同步多路复用模型,多线程作业讲解,生成消费者问题读写者问题,生产和消费者问题,生成者缓冲区慢,等待缓冲区未满,生成产品,放入缓冲区,通知消费者消费者缓冲区空,等待缓冲区非空,从缓冲区取出产品,通知生成者,读写者问题,任意多的读进程可以同时读缓冲区;一次只允许一个写进程往缓冲区写;如果一个写进程正在往缓冲区写,禁止任何读进程或写进程访问缓冲区;写进程执行写操作前,应让已有的写者或读者全部退出。,读写者问题,实现 viewthread&tid=3305,多路复用模型,阻塞、非阻塞、异步和同步,概念示例适用点,阻塞模型,用打电话为例,阻塞模型是不停的给对方打电话,直到电话打通为止。,因为在一个阻塞套接字上调用任何一个Winsock API函数,都会产生相同的后果-耗费或长或短的时间等待,所以对于处在阻塞模式的套接字,必须多加留意,非阻塞模型,用打电话为例,非阻塞模型是给对方打电话,如果电话不通,则过一会再打。,非阻塞模型,SOCKET s;unsigned long flag=1;intret;s=socket(AF_INET,SOCKET_STREAM,0);nRet=ioctlsocket(s,FIONBIO,(unsigned long*)if(ret=SOCKET_ERROR)/未能将套接字置入非阻塞模式,非阻塞模型,将一个套接字置为非阻塞模式之后,处理收发数据或处理连接的Winsock API调用会立即返回。大多数情况下,这些调用在失败时会返回一个WSAWOULDBLOCK错误,这意味着请求的操作在调用期间没有足够时间来完成。举个例子来说,假如在系统的输入缓冲区中,尚不存在被挂起的数据,那么recv调用就会返回WSAWOULDBLOCK错误。通常,需要重复调用同一个函数,直到获得成功的返回代码,异步模型,用打电话为例,异步模型是给对方打电话,如果电话不通,则等待对方打过来。,多路复用模型,select(选择)模型是Winsock中另一个应用广泛的I/O模型。它的工作原理是利用select函数,实现对I/O的管理。select函数可用于判断套接字上是否存在数据,或者能否向一个套接字写入数据。之所以使用这个函数,其目的是:防止应用程序处于阻塞模式中时,在I/O绑定调用(如send或recv)过程中进入阻塞状态;同时也防止在套接字处于非阻塞模式中时,产生WSAWOULDBLOCK错误,Select 函数,除非满足事先用参数规定的条件,否则select函数在进行I/O操作时会阻塞。select函数额原型如下:int select(int nfds,fd_set FAR*readfds,fd_set FAR*writefds,fd_set FAR*exceptfds,const struct timeval FAR*timeout);,其中nfds参数会被忽略。这里有三个fd_set参数:一个用于检查可读性(readfds),一个用于检查可写性(writefds),另一个用于带外数据(exceptfds)。从根本上说,fd_set数据类型代表着一系列特定套接字的集合。,假定我们想测试一个套接字是否可读,必须将这个套接字添加到readfds,再等待select函数完成。当select调用完成,必须判断这个套接字是否仍为readfds集合的一部分。在三个参数(readfds、writefds和exceptfds),任何两个都可以是空值(NULL);但是,至少有一个不能为空值。,最后一个参数timeout对应的是一个指针,它指向一个timeval结构,用于决定select等待I/O操作完成时,最多等待多长的时间。如果timeout是一个空指针,那么select调用会无限期处于阻塞状态,直到至少有一个描述符与指定的条件相符后才结束。对timeval结构的定义如下:struct timevallong tv_sec;/以秒为单位指定等待时间long tv_usec;/以毫秒为单位指定等待时间;,若将超时值设置为0,0,表明select会立即返回,允许应用程序对select操作进行轮讯。但出于性能考虑,应避免这样的设置。当select成功返回后,会在fd_set结构中,返回被挂起的I/O操作的所有套接字句柄的总量。,Winsock提供了下列宏操作,可用来针对I/O活动,对fd_set集合进行处理与检查:FD_ZERO(*set)FD_CLR(s,*set)FD_ISSET(s,*set)FD_SET(s,*set),Select 模型,Select 模型,采用select模型的echo客户端和服务端Select示例使用select的优势是,能够从单个线程的多个套接字上进行多重连接及I/O。这就避免了伴随阻塞套接字和多重连接的线程剧增,