
fdset参数一个用于检查可读性(readfds).doc
7页fd_set参数:一个用于检查可读性(readfds),一个用于检查可写性(writefds),另一个用于例外数据(exceptfds)从根本上说,fd_set数据类型代表着一系列特定套接字的集合其中,readfds集合包括符合下述任何一个条件的套接字:■有数据可以读入■连接已经关闭、重设或中止■假如已调用了listen,而且一个连接正在建立,那么accept函数调用会成功writefds集合包括符合下述任何一个条件的套接字:■有数据可以发出■如果已完成了对一个非锁定连接调用的处理,连接就会成功最后,exceptfds集合包括符合下述任何一个条件的套接字:■假如已完成了对一个非锁定连接调用的处理,连接尝试就会失败■有带外(Out-of-band,OOB)数据可供读取用select对套接字进行监视之前,在自己的应用程序中,必须将套接字句柄分配给一个集合,设置好一个或全部读、写以及例外fd_set结构将一个套接字分配给任何一个集合后,再来调用select,便可知道一个套接字上是否正在发生上述的I/O活动Winsock提供了下列宏操作,可用来针对I/O活动,对fd_set进行处理与检查:■FD_CLR(s,*set):从set中删除套接字s。
■FD_ISSET(s,*set):检查s是否set集合的一名成员;如答案是肯定的是,则返回TRUE■FD_SET(s,*set):将套接字s加入集合set■FD_ZERO(*set):将set初始化成空集合例如,假定我们想知道是否可从一个套接字中安全地读取数据,同时不会陷于无休止的“锁定”状态,便可使用FD_SET宏,将自己的套接字分配给fd_read集合,再来调用select要想检测自己的套接字是否仍属fd_read集合的一部分,可使用FD_ISSET宏采用下述步骤,便可完成用select操作一个或多个套接字句柄的全过程:1)使用FD_ZERO宏,初始化自己感兴趣的每一个fd_set2)使用FD_SET宏,将套接字句柄分配给自己感兴趣的每个fd_set3)调用select函数,然后等待在指定的fd_set集合中,I/O活动设置好一个或多个套接字句柄select完成后,会返回在所有fd_set集合中设置的套接字句柄总数,并对每个集合进行相应的更新4)根据select的返回值,我们的应用程序便可判断出哪些套接字存在着尚未完成(待决)的I/O操作—具体的方法是使用FD_ISSET宏,对每个fd_set集合进行检查。
5)知道了每个集合中“待决”的I/O操作之后,对I/O进行处理,然后返回步骤1),继续进行select处理select返回后,它会修改每个fd_set结构,删除那些不存在待决I/O操作的套接字句柄若WSAWaitForMultipleEvents收到一个事件对象的网络事件通知,便会返回一个值,指出造成函数返回的事件对象这样一来,我们的应用程序便可引用事件数组中已传信的事件,并检索与那个事件对应的套接字,判断到底是在哪个套接字上,发生了什么网络事件类型对事件数组中的事件进行引用时,应该用WSAWaitForMultipleEvents的返回值,减去预定义值WSA_WAIT_EVENT_0,得到具体的引用值(即索引位置)如下例所示:知道了造成网络事件的套接字后,接下来可调用WSAEnumNetworkEvents函数,调查发生了什么类型的网络事件该函数定义如下:s参数对应于造成了网络事件的套接字hEventObject参数则是可选的;它指定了一个事件句柄,对应于打算重设的那个事件对象由于我们的事件对象处在一个“已传信”状态,所以可将它传入,令其自动成为“未传信”状态如果不想用hEventObject参数来重设事件,那么可使用WSAResetEvent函数,该函数早先已经讨论过了。
最后一个参数是lpNetworkEvents,代表一个指针,指向WSANETWORKEVENTS结构,用于接收套接字上发生的网络事件类型以及可能出现的任何错误代码下面是WSANETWORKEVENTS结构的定义:创建套接字的时候,假如使用的是socket函数,而非WSASocket函数,那么会默认设置WSA_FLAG_OVERLAPPED标志成功建好一个套接字,同时将其与一个本地接口绑定到一起后,便可开始进行重叠I/O操作,方法是调用下述的Winsock函数,同时指定一个WSAOVERLAPPED结构(可选):■WSASend■WSASendTo■WSARecv■WSARecvFrom■WSAIoctl■AcceptEx■TrnasmitFileWSAOVERLAPPED结构在一个重叠I/O请求的初始化,及其后续的完成之间,提供了一种沟通或通信机制下面是这个结构的定义:发现一次重叠请求完成之后,接着需要调用WSAGetOverlappedResult(取得重叠结构)函数,判断那个重叠调用到底是成功,还是失败该函数的定义如下:2.完成例程“完成例程”是我们的应用程序用来管理完成的重叠I/O请求的另一种方法。
完成例程其实就是一些函数最开始的时候,我们将其传递给一个重叠I/O请求,在一个重叠I/O请求完成时由系统调用它们的基本设计宗旨是通过调用者的线程,为一个已完成的I/O请求提供服务除此以外,应用程序可通过完成例程,继续进行重叠I/O处理如果希望用完成例程为重叠I/O请求提供服务,在我们的应用程序中,必须为一个I/O定界Winsock函数,指定一个完成例程,同时指定一个WSAOVERLAPPED结构一个完成例程必须拥有下述函数原型:在程序清单8-8中,我们向大家展示了如何构建一个简单的服务器应用,令其采用前述的方法,通过完成例程,来实现对一个套接字请求的管理该程序的编码主要按下述步骤进行:1)新建一个套接字,开始在指定端口上,监听一个进入的连接2)接受一个进入的连接请求3)为接受的套接字创建一个WSAOVERLAPPED结构4)在套接字上投递一个异步WSARecv请求,方法是将WSAOVERLAPPED指定成为参数,同时提供一个完成例程5)在将fAlertable参数设为TRUE的前提下,调用WSAWaitForMultipleEvents,并等待一个重叠I/O请求完成重叠请求完成后,完成例程会自动执行,而且WSAWaitForMultipleEvents会返回一个WSA_IO_COMPLETION。
在完成例程内,可随一个完成例程一道,投递另一个重叠WSARecv请求6)检查WSAWaitForMultipleEvents是否返回WSA_IO_COMPLETION7)重复步骤5)和6)我们的应用程序可用Win32的SleepEx函数将自己的线程置为一种可警告等待状态该函数也设计用于将我们的线程置入一种可警告等待状态,并可为已经完成的重叠I/O请求进行完成例程的处理(前提是将fAlertable参数设为TRUE)用一个完成例程结束了重叠I/O请求之后,返回值是WSA_IO_COMPLETION,而不是事件数组中的一个事件对象索引SleepEx函数的行为实际上和WSAWaitForMultipleEvents差不多,只是它不需要任何事件对象对SleepEx函数的定义如下:dwMilliseconds参数定义了SleepEx函数的等待时间,以毫秒为单位假如将dwMilliseconds设为INFINITE,那么SleepEx会无休止地等待下去bAlertable参数规定了一个完成例程的执行方式假如将bAlertable设为FALSE,而且进行了一次I/O完成回调,那么I/O完成函数不会执行,而且函数不会返回,除非超过由dwMilliseconds规定的时间。
若设为TRUE,那么完成例程会得到执行,同时SleepEx函数返回WAIT_IO_COMPLETION从本质上说,完成端口模型要求我们创建一个Win32完成端口对象,通过指定数量的线程,对重叠I/O请求进行管理,以便为已经完成的重叠I/O请求提供服务要注意的是,所谓“完成端口”,实际是Win32、WindowsNT以及Windows2000采用的一种I/O构造机制,除套接字句柄之外,实际上还可接受其他东西然而,本节只打算讲述如何使用套接字句柄,来发挥完成端口模型的巨大威力使用这种模型之前,首先要创建一个I/O完成端口对象,用它面向任意数量的套接字句柄,管理多个I/O请求要做到这一点,需要调用CreateCompletionPort函数该函数定义如下:intraweb(★人贱人爱★)在我们深入探讨其中的各个参数之前,首先要注意该函数实际用于两个明显有别的目的:■用于创建一个完成端口对象■将一个句柄同完成端口关联到一起对完成端口来说,将一个套结字邦定到完成端口后,WSARecv和WSASend会立即返回,提高了系统的效率可以调用GetQueuedCompletionStatus来判断WSARecv和WSASend是否完成。
这样主程序就可以完全等待接受新的连接,线程程序来等待WSARecv和WSASend是否完成了我想这也是完成端口的真正含义吧完成端口一个完成端口其实就是一个通知队列,由操作系统把已经完成的重叠I/O请求的通知放入其中当某项I/O操作一旦完成,某个可以对该操作结果进行处理的工作者线程就会收到一则通知而套接字在被创建后,可以在任何时候与某个完成端口进行关联通常情况下,我们会在应用程序中创建一定数量的工作者线程来处理这些通知线程数量取决于应用程序的特定需要理想的情况是,线程数量等于处理器的数量,不过这也要求任何线程都不应该执行诸如同步读写、等待事件通知等阻塞型的操作,以免线程阻塞每个线程都将分到一定的CPU时间,在此期间该线程可以运行,然后另一个线程将分到一个时间片并开始执行如果某个线程执行了阻塞型的操作,操作系统将剥夺其未使用的剩余时间片并让其它线程开始执行也就是说,前一个线程没有充分使用其时间片,当发生这样的情况时,应用程序应该准备其它线程来充分利用这些时间片其实可以把完成端口看成是系统维护的一个队列,操作系统把重叠的I/O操作完成的事件通知放到该队列中,由于是“操作完成”的事件通知所以命名为“完成端口”//----------------------------------------------------------------------------------系统为你开一根内部线程去处理I/O请求////////////////////////////////////////////////你这个说法有误,可以参考DDK中WDM驱动文档系统不会新开内部线程来等待,它只是简单交给设备去处理IO直到设备以它自己的方式(多数是中断,即使有DMA)通知CPU,IO操作完成,系统(多数是响应中断时)再通知Iocp(就是挂个消息了)因此,Iocp就是一个消息队列//----------------------------------------------------------------------------------我们基本上按下述步骤行事:1)创建一个完成端口。
第四个参数保持为0,指定在完成端口上,每个处理器一次只允许执行一个工作者线程2)判断系统内到底安装了多少个处理器。
