网络程序设计IOCP与可伸缩网络程序.ppt
《网络程序设计IOCP与可伸缩网络程序.ppt》由会员分享,可在线阅读,更多相关《网络程序设计IOCP与可伸缩网络程序.ppt(126页珍藏版)》请在课桌文档上搜索。
1、18:36:20,1,第四章,IOCP与可伸缩网络程序,18:36:20,2,回顾前4种IO模型,摘自互联网场景:在风景秀丽的海边别墅,住着一位老人,他有一个在外地工作的女儿,不能经常回来,老人和她通过信件联系,邮递员把信件投递到他们的信箱里。老人:应用程序信箱:套接字,18:36:20,3,select模型:老人非常想看到女儿的信,每隔10分钟就下楼检查信箱,看是否有女儿的信。select模型周而复始地去检查套接字.如果有数据或者可以发送数据.接收/发送.while(1)int ret=select();.,18:36:20,4,WSAAsyncSelect模型 微软公司改进信箱,采用一种新
2、式信箱,这种信箱非常先进,一旦信箱里有新的信件,微软就会发短信通知老人:喂,大爷,你有新的信件了!于是,老人下楼取信处理信件 WSAAsyncSelect()函数安装新式信箱,在套接字上注册网络事件并关联到窗口。使用WSAAsyncSelect模型时,Windows会把网络事件以消息的形式通知应用程序。,18:36:20,5,WSAEventSelect模型 微软的新式信箱非常畅销,购买微软信箱的人以百万计数以至于盖茨每天24小时发短信通知客户有信件到达,于是微软又改进了他们的信箱:在客户的家中添加一个附加装置,这个装置会监视客户的信箱,每当新的信件来临,此装置会发出“新信件到达”声,提醒老人
3、下楼去收信。WSAEventSelect()函数安装这个新式信箱,将套接字和事件对象相关联。WSAEventSelect模型在套接字上注册网络事件,网络事件发生时,应用程序通过事件对象状态的变化感知网络事件的发生。,18:36:20,6,Overlapped I/O 事件通知模型 微软调查发现:老人不喜欢上下楼收发信件,因为上下楼其实很浪费时间。于是微软再次改进信箱,采用了更为先进的技术,只要用户告诉老人家在几楼几号,新式信箱会把信件直接传送到用户的家中,然后告诉用户,你的信件已经放到你的家中了!老人很高兴,因为他不必再亲自下楼收发信件了!提供门牌号码相当于提供缓冲区并投递IO操作。Overl
4、apped模型是让应用程序使用重叠数据结构,一次投递一个或多个Winsock I/O请求。这些提交的请求完成后,应用程序会收到完成通知。从socket上接收数据,只需要告诉系统要接收数据,而数据的接收由系统完成,应用程序需要做的只是为系统提供一个缓冲区,18:36:20,7,IOCP模型 微软信箱似乎很完美,老人很满意。但是在一些大公司情况却完全不同,每秒钟都有数以百计的信件需要处理,以至于微软信箱经常因超负荷运转而崩溃!问题在于:在一个套接字上投递大量的IO操作,处理IO的结果需要等待的时间变长如何解决?增加信箱,18:36:20,8,方案一,while(TRUE)NewConnection
5、=accept(ListeningSocket,(SOCKADDR*),18:36:20,9,Windows NT小组注意到这些应用程序的性能没有预料的那么高。特别是处理很多同时的客户请求,意味着很多线程并发地运行在系统中。因为所有这些线程都是可运行的没有被挂起和等待发生什么事,Microsoft意识到NT内核花费了太多的时间来转换运行线程的上下文Context,线程就没有得到很多CPU时间来做它们的工作。这种并行模型的瓶颈在于它为每一个客户请求都创建了一个新线程,创建线程比起创建进程开销要小,但也远不是没有开销的。-摘自nonocast的理解I/O Completion Port,18:36
6、:20,10,方案二,不妨设想一下:如果事先开好N个线程,让它们在那hold阻塞,然后可以将所有用户的请求都投递到一个消息队列中去,然后N个线程逐一从消息队列中去取出消息并加以处理,就可以避免针对每一个用户请求都开线程。不仅减少了线程的资源,也提高了线程的利用率。理论上很不错,你想我等泛泛之辈都能想出来的问题,Microsoft又怎会没有考虑到呢?-摘自nonocast的理解I/O Completion Port也就是采用IO完成端口,18:36:20,11,关于IOCP的几个评述,I/O完成端口可能是Win32提供的最复杂的内核对象。Advanced Windows 3rd Jeffrey
7、Richter IOCP是实现高容量网络服务器的最佳方法。Windows Sockets2.0:Write Scalable Winsock Apps Using Completion Ports Microsoft Corporation 完成端口模型提供了最好的伸缩性。这个模型非常适用来处理数百乃至上千个套接字。Windows网络编程 2nd Anthony Jones&Jim Ohlund I/O completion ports特别重要,是唯一适用于高负载服务器的技术。Completion ports利用一些线程,帮助平衡由I/O请求所引起的负载。Win32多线程程序设计 Jim Be
8、veridge&Robert Wiener,18:36:20,12,IOCP,Windows NT3.5中首次引入了一个称为I/O完成端口的内核对象;微软在Winsock2中引入了IOCP这一概念。IOCP全称I/O Completion Port,中文译为I/O完成端口。IOCP就是一个消息队列;IOCP是应用程序和操作系统沟通的一个接口。套接字与完成端口关联后就可投递Winsock IO操作。当IO操作完成后,完成端口会收到IO系统的通知包并将这些通知加入到一个队列中,然后应用程序可以查询完成端口取得通知包。如何使用完成端口:创建与查询,18:36:20,13,完成端口I/O模型,I/O完
9、成端口是应用程序使用线程池处理异步I/O请求的一种机制。处理多个并发异步I/O请求时,使用I/O完成端口比在I/O请求时创建线程更快更有效。完成端口可接受多种对象句柄。从本质上说,完成端口模型要求创建一个Win32完成端口对象,通过指定数量的线程,对重叠I/O请求完成情况进行管理,以便为已经完成的重叠I/O请求提供服务。,18:36:20,14,创建完成端口HANDLE CreateIoCompletionPort(HANDLE FileHandle,/handle to file HANDLE ExistingCompletionPort,/handle to I/O completion
10、port DWORD CompletionKey,/completion key DWORD NumberOfConcurrentThreads/number of threads to execute concurrently);函数功能:用于创建一个完成端口对象。将一个句柄同完成端口关联到一起。,FileHandle:一个已打开的文件句柄,该句柄创建时必须使用FILE_FLAG_OVERLAPPED 标志。该参数若为INVALID_HANDLE_VALUE,则创建一个没有任何文件相关联的完成端口,此时ExistingCompletionPort必须为NULL,CompletionKey被忽
11、略。ExistingCompletionPort:指向完成端口的句柄。该参数若指定了一个已存在的完成端口,则将该完成端口与由FileHandle指定的文件相关联,函数返回值就为该完成端口;若没有指定,为NULL,则创建一个完成端口并实施关联,函数返回新创建的完成端口。CompletionKey:完成键,指定句柄唯一数据,可存放用户定义的任意类型的数据,通常是一个指针。NumberOfConcurrentThreads:系统允许的并发最大线程数,若为0,则线程数和CPU数量相同。,18:36:20,15,18:36:20,16,功能1、创建完成端口对象 HANDLE hCompletion=:C
12、reateCompletionPort(INVALID_HANDLE_VALUE,0,0,0);在创建完成端口时,只需填写NumberOfConcurrentThreads参数,告诉系统完成端口上同时允许运行的线程最大数。在默认情况下,所开线程数和CPU数量相同,经验公式为:线程数=CPU数*2+2 作用是返回一个句柄,在为完成端口分配了一个套接字句柄后,用来对该完成端口进行引用。功能2、将一个句柄同完成端口关联起来 CreateIoCompletionPort(s,hCompletion,(DWORD)pPerHandle,0);,18:36:20,17,I/O服务线程与完成端口在关联套接字
13、之前,首先必须创建一个或多个工作线程,以便在I/O请求投递给完成端口对象后,为完成端口提供服务。工作线程数目原则和创建完成端口时指定的NumberOfConcurrentThreads相同,根据程序总体设计可以适当增加。,18:36:20,18,完成端口和重叠I/O将套接字句柄与一个完成端口关联在一起后,便可以套接字句柄为基础,投递发送与接收请求。I/O操作完成时,I/O系统向完成端口对象发送一个完成通知包。I/O完成端口以先进先出方式为通知包排队。应用程序使用GetQueuedCompletionStatus函数获得通知包,18:36:20,19,BOOL GetQueuedCompleti
14、onStatus(HANDLE CompletionPort,/handle to completion port LPDWORD lpNumberOfBytes,/bytes transferred LPDWORD lpCompletionKey,/file completion key LPOVERLAPPED*lpOverlapped,/buffer DWORD dwMilliseconds/optional timeout value);GetQueuedCompletionStatus()使调用线程挂起,直到指定的端口的I/O完成队列中出现了一项完成通知包或直到超时。,Complet
15、ionPort:指定线程要在查询的完成端口。很多服务应用程序只使用一个I/O完成端口,所有的I/O请求完成以后的通知都将发给该端口。lpNumberOfBytes:接收实际传输的字节数。lpCompletionKey:关联套接字到完成端口时的句柄唯一数据。lpOverlapped:投递IO操作时使用的重叠结构。dwMilliseconds:等待时间。同I/O完成端口相关联的3个数据结构是使线程得到完成I/O项中的信息:传输的字节数,句柄唯一数据和OVERLAPPED结构的地址。这些信息通过传递给GetQueuedCompletionSatatus的lpdwNumberOfBytesTransf
16、erred,lpdwCompletionKey和lpOverlapped参数返回给线程的。,18:36:20,20,函数返回值:非0:表示取得IO成功的通知包lpdwNumberOfBytesTransferred,lpdwCompletionKey和lpOverlapped三个参数指定的存储单元值被更新0:当lpOverlapped=NULL且函数没有取得完成通知包,此时lpdwNumberOfBytesTransferred,lpdwCompletionKey指定存储单元值不被更新;当lpOverlapped!=NULL且取得IO失败的通知包,此时lpdwNumberOfBytesTran
17、sferred,lpdwCompletionKey和lpOverlapped三个参数指定的存储单元值被更新,18:36:20,21,18:36:20,22,句柄唯一数据和I/O唯一数据一个工作线程从GetQueuedCompletionStatus调用接收到I/O完成通知后,在lpCompletionKey和lpOverlapped参数中,包含一些必要的套接字信息和I/O信息,利用这些信息可通过完成端口,继续在一个套接字上的I/O处理。通过这些参数,可获得两方面重要的与套接字相关的数据:句柄唯一数据以及I/O唯一数据。,18:36:20,23,lpCompletionKey参数包含了“句柄唯一
18、数据”,通常情况下,应用程序会将与I/O请求有关的套接字句柄保存在这里。lpOverlapped参数则包含了一个OVERLAPPED结构,在它后面跟随“I/O唯一数据”。I/O唯一数据可以是追加到一个OVERLAPPED结构末尾的、任意数量的字节。如果一个函数要求用到一个OVERLAPPED结构,就必须将这样的一个结构传递进去,以满足它的要求。解决方法是定义一个结构,将OVERLAPPED结构作为新结构的第一个元素使用。,18:36:20,24,typedef struct _PER_IO_DATA/per-I/O数据OVERLAPPED ol;/重叠结构char bufBUFFER_SIZE
19、;/数据缓冲区int nOperationType;/操作类型#define OP_READ 1#define OP_WRITE 2#define OP_ACCEPT 3 PER_IO_DATA,*PPER_IO_DATA;,typedef struct _PER_HANDLE_DATA/per-handle数据SOCKET s;/对应的套接字句柄sockaddr_in addr;/客户方地址 PER_HANDLE_DATA,*PPER_HANDLE_DATA;,关闭IOCP,要避免在进行重叠I/O操作的同时,强行释放一个OVERLAPPED结构,最好的办法是针对每个套接字句柄,调用close
20、socket函数,任何尚未进行的重叠I/O操作都会完成,只不过是失败方式完成。一旦所有套接字句柄都已关闭,便需在完成端口上 终止所有工作线程的运行,则需要使用PostQueuedCompletionStatus()函数,向每个工作线程都发送一个指示每个线程都“立即结束并退出”完成通知包。,18:36:20,25,PostQueuedCompletionStatus函数原型:BOOL PostQueuedCompletionStatus(HANDLE CompletionPort,DWORD dwNumberOfBytesTransferred,ULONG_PTR dwCompletionKey
21、,LPOVERLAPPED lpOverlapped);后面3个参数指定的值会在调用GetQueuedCompletionStatus()函数时获得。,18:36:20,26,18:36:20,27,完成端口大概的处理流程,1:创建一个完成端口。2:创建一个线程A。3:A线程循环调用GetQueuedCompletionStatus()函数来得到IO操作结果。4:主线程循环里调用accept等待客户端连接。5:主线程里accept返回新连接后,把这个新的套接字句柄用CreateIoCompletionPort()关联到完成端口,然后发出一个异步的WSASend或WSARecv调用,因为是异步函
22、数,WSASend/WSARecv会马上返回,实际的发送或者接收操作由WINDOWS系统去做。,18:36:20,28,6:主线程继续下一次循环,阻塞在accept这里等待客户端连接。7:WINDOWS系统完成WSASend或者WSArecv的操作,把结果发到完成端口。8:A线程里的GetQueuedCompletionStatus()马上返回,并从完成端口取得刚完成的WSASend/WSARecv的结果。9:在A线程里对这些数据进行处理(如果处理过程很耗时,需要新开线程处理),然后接着发出WSASend/WSARecv,并继续下一次循环阻塞在GetQueuedCompletionStatus
23、()这里。,18:36:20,29,18:36:20,30,举例:主线程编程步骤,1、创建一个完成端口。2、判断系统处理器数目。3、根据步骤2 得到的处理器数量,创建工作线程,在完成端口上为已完成的I/O请求提供服务。4、准备好监听套接字,在端口*上监听进入的连接请求。5、使用accep t函数,接受进入的连接请求。6、创建一个数据结构,用于容纳“句柄唯一数据”,同时在结构中存入接受的套接字句柄。,18:36:20,31,7、调用CreateIoCompletionPort,将自accept返回的新套接字句柄同完成端口关联到一起。通过完成键(CompletionKey)参数,将句柄唯一数据结构
24、传递给CreateIoCompletionPort。8、开始在已接受的连接上投递I/O操作。9、重复步骤5)8),直至服务器中止。,18:36:20,32,InitWinsock()/加载Winsock库/步骤一,创建一个完成端口 CompletionPort=CreateIoCompletionPort(INVALI_HANDLE_VALUE,0,0,0);/步骤二判断系统处理器数目 GetSystemInfo(,18:36:20,33,/步骤四:创建监听套接字Listen=WSASocket(AF_INET,S0CK_STREAM,0,NULL,WSA_FLAG_OVERLAPPED);I
25、nternetAddr.sin_famlly=AF_INET;InternetAddr.sin_addr.s_addr=inet_addr(“127.0.0.1”);InternetAddr.sln_port=htons(6666);bind(Listen,(PSOCKADDR),18:36:20,34,/步骤六 创建一个数据结构,用于容纳“句柄唯一数据”,同时在结构中存入接受的套接字句柄。PerHandleData=(LPPER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA);printf(Socket number%d connec
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 网络程序设计 IOCP 伸缩 网络 程序

链接地址:https://www.desk33.com/p-259991.html