《网络编程实用教程_第6章.ppt》由会员分享,可在线阅读,更多相关《网络编程实用教程_第6章.ppt(71页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、吉林大学软件学院吉林大学软件学院期末大作业期末大作业l聊天类程序。聊天类程序。l语言:限语言:限C、C+、Javal提交材料:提交材料:l设计方案(纸介质);l类图(纸介质);l运行界面截图(纸介质);l源码中设计socket编程部分的详细注释(纸介质);l5个以上错误调试的截图、解决办法说明(纸介质);l源代码(电子版,发至socket_,文件名为姓名学号)l纸介质中的每项占纸介质中的每项占15分,源代码分,源代码15分,平时分,平时10分。分。吉林大学软件学院吉林大学软件学院2第第5章章 WinSock的多线程编程及的多线程编程及I/O模型模型lWinSock需要多线程编程的原因,需要多线
2、程编程的原因,lWin32操作系统下的多进程多线程机制、多操作系统下的多进程多线程机制、多线程机制在网络编程中的应用线程机制在网络编程中的应用l五种非阻塞工作模式五种非阻塞工作模式下的下的“套接字套接字I/O模型模型”吉林大学软件学院吉林大学软件学院35.1WinSock为什么需要多线程编程为什么需要多线程编程5.1.1WinSock的两种的两种I/O模式模式l“阻塞阻塞”模式,模式,又称为同步模式,执行又称为同步模式,执行I/O操作完操作完成前会一直进行等待,不会将控制权交给程序,成前会一直进行等待,不会将控制权交给程序,工作在工作在“阻塞阻塞”模式的套接字模式的套接字称为阻塞套接字。称为阻
3、塞套接字。l套接字 默认为阻塞模式。l可以通过多线程技术进行处理。l“非阻塞非阻塞”模式,模式,又称为异步模式,执行又称为异步模式,执行I/O操作操作时,时,Winsock函数会返回并交出控制权。工作在函数会返回并交出控制权。工作在“非阻塞非阻塞”模式下的套接字模式下的套接字称为非阻塞套接字。称为非阻塞套接字。l使用 起来比较复杂,因为函数在没有运行完成就进行返回,会不断地返回WSAEWOULDBLOCK错误,但功能强大。吉林大学软件学院吉林大学软件学院4l在大多数情况下,非阻塞模式调用都会失败,返回一个WSAEWOULDBLOCK错误,表示操作的条件尚不具备,但又不允许等待完成请求的操作。l
4、非阻塞模式下会频繁返回错误,应仔细检查返回代码;并且在不成功的情况下 不应反复轮询.吉林大学软件学院吉林大学软件学院55.1.2两种模式的优缺点及解决方法两种模式的优缺点及解决方法l“阻塞阻塞”与与“非阻塞非阻塞”模式各有其优点和缺点。模式各有其优点和缺点。l阻塞套接字阻塞套接字,I/O操作工作情况比较确定,无非是操作工作情况比较确定,无非是调用、等待、返回,大部分情况下调用、等待、返回,大部分情况下I/O操作都能成操作都能成功地完成,不过就是花费了等待的时间。功地完成,不过就是花费了等待的时间。l因而比较容易使用,容易编程;l但在应付诸如需要建立多个套接字连接来为多个客户服务的时候,或在数据
5、的收发量不均匀的时候,或在输入输出的时间不确定的时候,却显得性能低下,甚至无能为力。吉林大学软件学院吉林大学软件学院6l非阻塞套接字非阻塞套接字,需要编写更多代码,因为必须恰,需要编写更多代码,因为必须恰当地把握调用当地把握调用I/O函数的时机,尽量减少无功而返函数的时机,尽量减少无功而返的调用,还必须详加分析每个的调用,还必须详加分析每个Winsock调用中收到调用中收到的的WSAEWOULDBLOCK错误,采取相应的对策错误,采取相应的对策.l这种I/O操作的随机性使得非阻塞套接字显得难于操作。l l必须采取适当的对策,克服这两种模式的缺点,必须采取适当的对策,克服这两种模式的缺点,必须采
6、取适当的对策,克服这两种模式的缺点,必须采取适当的对策,克服这两种模式的缺点,让阻塞和非阻塞套接字能够满足各种场合的要求让阻塞和非阻塞套接字能够满足各种场合的要求.l对于阻塞的套接字工作模式,则进一步引入了多线程机制。l对于非阻塞的套接字工作模式,进一步引入了五种“套接字I/O模型”。吉林大学软件学院吉林大学软件学院75.2Win32操作系统下的操作系统下的多进程多线程机制多进程多线程机制5.2.1Win32是单用户多任务的操作系统是单用户多任务的操作系统l微软最早的微软最早的DOS是单用户单任务的。是单用户单任务的。l后来的图形用户界面操作系统后来的图形用户界面操作系统Windows,发展到
7、,发展到Windows95、Windows98,就都支持多任务了;,就都支持多任务了;l从从WindowsNT起,起,Windows发展成了一个真正的发展成了一个真正的抢占式多任务操作系统。抢占式多任务操作系统。l一个运行中的应用进程实例,就是一个进程。l一个基于Win32的应用程序可以包含一个或多个进程。吉林大学软件学院吉林大学软件学院5.2.2Win32OS是支持多线程的操作系统是支持多线程的操作系统lWin32操作系统还支持同一进程的多线程,在一个操作系统还支持同一进程的多线程,在一个Windows进程内,可以包含多个线程。进程内,可以包含多个线程。l一个线程一个线程(thread)是进
8、程内的一条执行路径,具体是进程内的一条执行路径,具体地说,是一个应用程序中的一条可执行路径,往地说,是一个应用程序中的一条可执行路径,往往是应用程序中的一个或多个函数。往是应用程序中的一个或多个函数。l一个进程中至少要有一个线程,习惯将它称一个进程中至少要有一个线程,习惯将它称为主为主线程线程。l任何一个应用程序进程都有一个主线程,一般任何一个应用程序进程都有一个主线程,一般C程程序中的序中的Main或或WinMain函数就规定了主线程的执函数就规定了主线程的执行代码。行代码。吉林大学软件学院吉林大学软件学院l当当你你启启动动了了一一个个应应用用程程序序时时,操操作作系系统统在在为为它它创创建
9、建了了进进程程之之后后,也也创创建建了了该该进进程程的的主主线线程程,并并根根据据Main或或WinMain函函数数的的地地址址,开开始始执执行行该该进进程程的主线程。的主线程。l主线程可以创建并启动其他主线程可以创建并启动其他辅助线程辅助线程;l由主线程创建的辅助线程又可以创建并启动更多由主线程创建的辅助线程又可以创建并启动更多的线程。的线程。l线程的代码执行完毕时会自动终止,并将占用的资源释放给进程;l进程的所有线程都终止时,进程也就终止了,并会将占用的资源释放给操作系统。吉林大学软件学院吉林大学软件学院105.2.3多线程机制在网络编程中的应用多线程机制在网络编程中的应用l如如果果一一个
10、个应应用用程程序序,有有多多个个任任务务需需要要同同时时进进行行处处理,那就最适合使用多线程机制。理,那就最适合使用多线程机制。l对于网络上客户机软件,采用多线程的编程技术,能克服在单线程的编程模式下,由于阻塞等待而产生的客户程序就不能及时响应用户的操作命令的问题,程序的界面就表现为类似死机的状态。l利利用用Windows系系统统的的多多线线程程机机制制可可以以很很好好的的解解决决这个问题。这个问题。l将用户界面的处理放在主线程中,将数据的I/O、费时的计算、网络访问等放在辅助线程里。吉林大学软件学院吉林大学软件学院11l网络上服务器软件应采用多线程的编程技术。网络上服务器软件应采用多线程的编
11、程技术。l能更好地为多个客户服务。l可以执行许多后台处理,如数据库访问、安全验证、日志记录、事物处理等。l客客户户机机软软件件,采采用用多多线线程程机机制制也也能能大大大大提提高高应应用用程序的运行效率。程序的运行效率。l如,东方快车、网络蚂蚁等文件下载软件,就采用了多线程机制,用多个线程同时下载一个文件的不同部分,大大加快了下载速度。l总之,多线程机制在网络编程中是大有作为总之,多线程机制在网络编程中是大有作为的。的。吉林大学软件学院吉林大学软件学院125.3Winsock的输入的输入/输出模型输出模型lWinSock的的I/O可以采用阻塞模式或非阻塞模式。可以采用阻塞模式或非阻塞模式。l在
12、非阻塞模式下,由于在非阻塞模式下,由于I/O操作的随机性,使非阻操作的随机性,使非阻塞套接字难于操作,给编程带来困难。塞套接字难于操作,给编程带来困难。l为解决这个问题,对于非阻塞的套接字工作模式,为解决这个问题,对于非阻塞的套接字工作模式,进一步引入了五种进一步引入了五种“套接字套接字I/O模型模型”,有助于应,有助于应用程序通过一种异步方式,同时对一个或多个套用程序通过一种异步方式,同时对一个或多个套接字上进行的通信加以管理。接字上进行的通信加以管理。13l这些模型包括:这些模型包括:lselect(选择)(选择)lWSAAsyncSelect(异步选择)(异步选择)lWSAEventSe
13、lect(事件选择)(事件选择)lOverlapped I/O(重叠式I/O)lCompletion port(完成端口)l不同的不同的Windows平台支持不同的平台支持不同的I/O模型。模型。平台平台选择选择异步选择异步选择事件选择事件选择重叠式重叠式I/O完成端口完成端口WindowsCE支持支持不支持不支持不支持不支持不支持不支持不支持不支持Windows95(WinSock1)支持支持支持支持不支持不支持不支持不支持不支持不支持Windows95(WinSock2)支持支持支持支持支持支持支持支持不支持不支持Windows98支持支持支持支持支持支持支持支持不支持不支持Windows
14、NT支持支持支持支持支持支持支持支持支持支持Windows2000支持支持支持支持支持支持支持支持支持支持吉林大学软件学院吉林大学软件学院145.4Select模型模型lSelect(选择选择)模型模型是是Winsock中最常见的中最常见的I/O模型。模型。l基本思想:是利用基本思想:是利用select函数,实现对多个套接字函数,实现对多个套接字I/O的管理。的管理。l利用select函数,可以判断一个或多个套接字的状态,某个套接字是否存在要读取的数据,或者能否向一个套接字写入数据;只有在条件满足时,才对套接字进行输入输出操作,从而避免无功而返的I/O函数调用,避免频繁产生WSAEWOULDB
15、LOCK错误,使I/O变得有序。吉林大学软件学院吉林大学软件学院151Select的函数的函数lselect的函数原型如下的函数原型如下l其中其中fd_set数据类型,代表一系列特定套接字集合数据类型,代表一系列特定套接字集合intselect(intnfds,/为保持兼容而设,可忽略fd_setFAR*readfds,fd_setFAR*writefds,fd_setFAR*exceptfds,conststructtimevalFAR*timeout/用于决定Select等待I/O操作完成的最长时间,若为空指针,则一直等待,直到至少有一个套接字符合条件。);吉林大学软件学院吉林大学软件学院
16、16lfd_set结构:结构:#defineFD_SETSIZE64;typedefstructfd_setu_intfd_count;/*howmanyareSET?*/SOCKETfd_arrayFD_SETSIZE;/*anarrayofSOCKETs*/fd_set;lfd_count为已设定socket的数量;lfd_array为socket列表;lFD_SETSIZE为最大socket数量,建议不小于64.吉林大学软件学院吉林大学软件学院17ltimeval结构:结构:structtimevallongtv_sec;/*seconds*/longtv_usec;/*andmicro
17、seconds*/;ltv_sec为时间的秒值。ltv_usec为时间的毫秒值。l这个结构主要是设置select()函数的等待值,如果将该结构设置为(0,0),则select()函数 会立即返回。182操作套接字集合的宏操作套接字集合的宏l在应用程序中,用在应用程序中,用select对套接字进行监视之前,对套接字进行监视之前,必须先将要检查的套接字句柄分配给某个集合,必须先将要检查的套接字句柄分配给某个集合,设置好相应的设置好相应的fd_set结构,再调用结构,再调用select函数。函数。lWinsock提供了提供了4个宏操作,专门对个宏操作,专门对fd_set数据类型数据类型进行操作进行操
18、作(1)FD_CLR(s,*set):从set中删除套接字s。(2)FD_ISSET(s,*set):检查s是否set集合的一名成员;如果是,则返回TRUE。(3)FD_SET(s,*set):将套接字s加入集合set。(4)FD_ZERO(*set):将set初始化成空集合。l其中,参数其中,参数s是一个要检查的套接字,参数是一个要检查的套接字,参数set是一是一个个fd_set集合类型的指针。集合类型的指针。吉林大学软件学院吉林大学软件学院19l例如,调用例如,调用select函数前,可使用函数前,可使用FD_SET宏,将宏,将指定的套接字加入到指定的套接字加入到fd_read集合中,集合
19、中,select函数完函数完成后,可使用成后,可使用FD_ISSET宏,来检查该套接字是宏,来检查该套接字是否仍在否仍在fd_read集合中。集合中。3select模型的操作步骤模型的操作步骤l用用select模型操作一个或多个套接字句柄,一般采模型操作一个或多个套接字句柄,一般采用下述步骤:用下述步骤:使用FD_ZERO宏,初始化自己感兴趣的每一个fd_set集合。使用FD_SET宏,将要检查的套接字句柄添加到自己感兴趣的每个fd_set集合中,相当在指定的fd_set集合中,设置好要检查的I/O活动。吉林大学软件学院吉林大学软件学院20调用select函数,然后等待。select完成返回后
20、,会修改每个fd_set结构,删除那些不存在待决I/O操作的套接字句柄,在各个fd_set集合中返回符合条件的套接字。根据select的返回值,使用FD_ISSET宏,对每个fd_set集合进行检查,判断一个特定的套接字是否仍在集合中,便可判断出哪些套接字存在尚未完成(待决)的I/O操作。知道了每个集合中“待决”的I/O操作之后,对相应的套接字的I/O进行处理,然后返回步骤1,继续进行select处理。吉林大学软件学院吉林大学软件学院215.5WSAAsyncSelect异步异步I/O模型模型l异步异步I/O模型模型通过调用通过调用WSAAsyncSelect()函数实现函数实现.l利用这个模
21、型,应用程序可在一个套接字上,接利用这个模型,应用程序可在一个套接字上,接收收以以Windows消息为基础的网络事件通知消息为基础的网络事件通知。l该模型的实现方法是通过调用WSAAsynSelect函数自动将套接字设置为非阻塞模式,并向WINDOWS注册一个或多个网络事件,并提供一个通知时使用的窗口句柄。l当注册的事件发生时,对应的窗口将收到一个基于消息的通知。l该模型最早出现于该模型最早出现于Winsock的的1.1中,以适应其多中,以适应其多任务消息环境。任务消息环境。吉林大学软件学院吉林大学软件学院221WSAAsyncSelect函数函数l函数的定义是:函数的定义是:intWSAAs
22、yncSelect(SOCKET s,/s为需要事件通知的套接字 HWNDhWnd,unsignedintwMsg,longlEvent);lhWnd为接收消息的窗口句柄 lwMsg为要接收的消息 llEvent为掩码,指定应用程序感兴趣的网络事件组合。吉林大学软件学院吉林大学软件学院232窗口回调例程窗口回调例程l应用程序在一个套接字上调用应用程序在一个套接字上调用WSAAsyncSelect函函数时,该函数的数时,该函数的hWnd参数指定了一个窗口句柄。参数指定了一个窗口句柄。l函数成功调用后,当指定的网络事件发生时,会自动执行该窗口对应的窗口回调例程。l并将网络事件通知和Windows消
23、息的相关信息,传递给该例程的入口参数,用户可以在该例程中添加自己的代码,针对不同的网络事件进行处理,从而实现有序的套接字输入和输出。吉林大学软件学院吉林大学软件学院24l窗口回调例程应定义成如下形式:窗口回调例程应定义成如下形式:LRESULTCALLBACKWindowProc(HWNDhWnd,UINTuMsg,WPARAMwParam,LPARAMlParam);吉林大学软件学院吉林大学软件学院5.6WSAEventSelect事件选择模型事件选择模型lWSAEventSelect事件选择模型和事件选择模型和WSAAsyncSelect模型类似,它也允许应用程序在一个或多个套接模型类似,
24、它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知。字上,接收以事件为基础的网络事件通知。l l该模型最主要的差别在于,网络事件会投递至一该模型最主要的差别在于,网络事件会投递至一该模型最主要的差别在于,网络事件会投递至一该模型最主要的差别在于,网络事件会投递至一个事件对象句柄,而非投递至一个窗口例程。个事件对象句柄,而非投递至一个窗口例程。个事件对象句柄,而非投递至一个窗口例程。个事件对象句柄,而非投递至一个窗口例程。l表表5.1总结的、由总结的、由WSAAsyncSelect模型采用的网络模型采用的网络事件,均可原封不动地移植到事件选择模型中。事件,均可原封不动地移植到事
25、件选择模型中。吉林大学软件学院吉林大学软件学院261创建事件对象句柄创建事件对象句柄l事件选择模型要求应用程序针对每一个套接字,事件选择模型要求应用程序针对每一个套接字,首先创建一个事件对象。首先创建一个事件对象。l创建方法是调用创建方法是调用WSACreateEvent函数,它的定义函数,它的定义如下:如下:WSAEVENTWSACreateEvent(void);l函数的返回值很简单,就是一个创建好的事件对函数的返回值很简单,就是一个创建好的事件对象句柄。象句柄。272关联套接字和事件对象,注册关心的网络事件关联套接字和事件对象,注册关心的网络事件l有了事件对象句柄后,接下来必须将其与某个
26、套接字有了事件对象句柄后,接下来必须将其与某个套接字关联在一起,同时注册感兴趣的网络事件类型(表关联在一起,同时注册感兴趣的网络事件类型(表5.1),需要调用),需要调用WSAEventSelect函数,函数的定义函数,函数的定义为:为:intWSAEventSelect(SOCKETs,/感兴趣的套接字WSAEVENThEventObject,/与套接字关联在一起的事件对象longlNetworkEvents /指定应用程序感兴趣的各种网络事件类型组合。);吉林大学软件学院吉林大学软件学院表表5.1用于用于WSAAsyncSelect函数的网络事件类型函数的网络事件类型事件类型事件类型含含义
27、义FD_READ应用程序想要接收有关是否有数据可读通知,以便读入数据应用程序想要接收有关是否有数据可读通知,以便读入数据FD_WRITE应用程序想要接收有关是否有可写通知,以便发送数据应用程序想要接收有关是否有可写通知,以便发送数据FD_OOB应用程序想要接收是否有应用程序想要接收是否有OOB数据抵达的通知数据抵达的通知FD_ACCEPT应用程序想要接收与进入的连接请求有关的通知应用程序想要接收与进入的连接请求有关的通知FD_CONNECT应用程序想要接收一次连接请求操作已经完成的通知应用程序想要接收一次连接请求操作已经完成的通知FD_CLOSE应用程序想要接收与套接字关闭有关的通知应用程序想
28、要接收与套接字关闭有关的通知293.等待网络事件触发事件对象句柄的工作状态等待网络事件触发事件对象句柄的工作状态l将一个套接字同一个事件对象句柄关联在一起以后,将一个套接字同一个事件对象句柄关联在一起以后,应用程序便可以调用应用程序便可以调用WSAWaitForMultipleEvents函数,函数,等待网络事件触发事件对象句柄的工作状态。等待网络事件触发事件对象句柄的工作状态。l该函数用来等待一个或多个事件对象句柄,当其中一该函数用来等待一个或多个事件对象句柄,当其中一个或所有句柄进入个或所有句柄进入“已传信已传信”状态后,或在超过了一状态后,或在超过了一个规定的时间期限后,立即返回。个规定
29、的时间期限后,立即返回。l该函数的定义:该函数的定义:DWORDWSAWaitForMultipleEvents(DWORDcEvents,constWSAEVENTFAR*lphEvents,BOOLfWaitAll,DWORDdwTimeout,BOOLfAlertable);吉林大学软件学院吉林大学软件学院304检查套接字上所发生的网络事件类型检查套接字上所发生的网络事件类型l确定了造成网络事件的套接字后,接下来可调用确定了造成网络事件的套接字后,接下来可调用WSAEnumNetworkEvents函数,检查套接字上发生函数,检查套接字上发生了什么类型的网络事件。了什么类型的网络事件。l
30、该函数定义如下:该函数定义如下:intWSAEnumNetworkEvents(SOCKETs,WSAEVENThEventObject,LPWSANETWORKEVENTSlpNetworkEvents);吉林大学软件学院吉林大学软件学院315处理网络事件处理网络事件l在确定了套接字上发生的网络事件类型后,可以根据在确定了套接字上发生的网络事件类型后,可以根据不同的情况做出相应的处理。不同的情况做出相应的处理。l完成了对完成了对WSANETWORKEVENTS结构中的事件的结构中的事件的处理之后,应用程序应在所有可用的套接字上,继续处理之后,应用程序应在所有可用的套接字上,继续等待更多的网络
31、事件。等待更多的网络事件。l应用程序完成了对一个事件对象的处理后,便应调用应用程序完成了对一个事件对象的处理后,便应调用WSACloseEvent函数,释放事件句柄使用的系统资源函数,释放事件句柄使用的系统资源.l函数的定义如下:函数的定义如下:BOOLWSACloseEvent(WSAEVENThEvent);l该函数也将一个事件句柄作为自己唯一的参数,并会该函数也将一个事件句柄作为自己唯一的参数,并会在成功后返回在成功后返回TRUE,失败后返回,失败后返回FALSE。吉林大学软件学院吉林大学软件学院5.7其它模型其它模型重叠(重叠(Overlapped)I/O模型模型l能使应用程序达到更佳
32、的性能。能使应用程序达到更佳的性能。l基本原理:基本原理:应用程序使用一个重叠的数据结构,一次应用程序使用一个重叠的数据结构,一次投递一个或多个投递一个或多个Winsock的的I/O请求,应用程序可为那请求,应用程序可为那些提交的请求提供服务。些提交的请求提供服务。l自自Winsock2.0发布开始,重叠发布开始,重叠I/O便已集成到新的便已集成到新的Winsock函数中,如函数中,如WSASend和和WSARecv等,适用于等,适用于安装了安装了Winsock2.0的所有的所有Windows平台。平台。l在一个套接字上使用重叠在一个套接字上使用重叠I/O模型,模型,首先,首先,首先,首先,必
33、须使用必须使用WSA_FLAG_OVERLAPPED标志创建一个套接字。标志创建一个套接字。s=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);吉林大学软件学院吉林大学软件学院33l使用使用socket函数函数,而非而非WSASocket函数创建套接字时,函数创建套接字时,会默认设置会默认设置WSA_FLAG_OVERLAPPED标志。标志。l建好一个套接字并将其绑定到一个本地接口后,便可建好一个套接字并将其绑定到一个本地接口后,便可调用下述的调用下述的Winsock函数开始进行重叠函数开始进行重叠I/O操作,同时操作,同
34、时指定一个指定一个WSAOVERLAPPED结构,函数依赖于结构,函数依赖于WSAOVERLAPPED结构来返回一个结构来返回一个I/O请求的返回请求的返回.WSASend、WSASendTo、WSARecv、WSARecvFrom、WSALoctl、AcceptEx、TrnasmitFilel以上每个函数都与一个套接字上数据的发送、数据接以上每个函数都与一个套接字上数据的发送、数据接收以及连接的接受有关,极少的时间内就能完成。收以及连接的接受有关,极少的时间内就能完成。l若随一个若随一个WSAOVERLAPPED结构一起调用,函数会结构一起调用,函数会立即完成并返回,无论套接字是否设为锁定模
35、式。立即完成并返回,无论套接字是否设为锁定模式。吉林大学软件学院吉林大学软件学院34l有两个方法可用来管理一个重叠有两个方法可用来管理一个重叠I/O请求:请求:l令应用程序等待“事件对象通知”;l通过“完成例程”对已经完成的请求加以处理.l前述函数(除前述函数(除AcceptEx外)还有一个常用参数:外)还有一个常用参数:lpCompletionROUTINEl该参数指定一个可选的指针,指向一个完成例程函数,该参数指定一个可选的指针,指向一个完成例程函数,在重叠请求完成后调用。在重叠请求完成后调用。1.事件通知事件通知l重叠重叠I/O模型的事件通知方法要求将模型的事件通知方法要求将Win32事
36、件对象与事件对象与WSAOVERLAPPED结构关联在一起。结构关联在一起。l若使用一个若使用一个WSAOVERLAPPED结构,发出结构,发出WSASend和和WSARecv这样的这样的I/O调用,会立即返回。调用,会立即返回。35l这这 些些 I/O调调 用用 通通 常常 以以 失失 败败 告告 终终,返返 回回SOCKET_ERROR,这这个个错错误误状状态态意意味味着着I/O操操作作正正在在进进行行,使使用用WSAGetLastError函函数数,可可获获得得与与错错误误状态有关的一个报告。状态有关的一个报告。l稍后,应用程序需要等候与稍后,应用程序需要等候与WSAOVERLAPPED
37、结构结构对应的事件对象,获知一个重叠对应的事件对象,获知一个重叠I/O请求何时完成。请求何时完成。lWSAOVERLAPPED结构在一个重叠结构在一个重叠I/O请求的初始请求的初始化及其后续完成之间,提供了一种沟通或通信机制。化及其后续完成之间,提供了一种沟通或通信机制。l下面是这个结构的定义:下面是这个结构的定义:typedef struct WSAOVERLAPPEDDWORD Internal;DWORD InternalHigh;DWORD Offset;DWORD OffsetHigh;WSAEVENT hEvent;WSAOVERLAPPED Far*LPWSAOVERLAPPED
38、吉林大学软件学院吉林大学软件学院36l在这个结构中在这个结构中:lInternal、InternalHigh、Offset和OffsetHigh字段由系统在内部使用,不应由应用程序直接处理或使用;lhEventh 字段允许应用程序将一个事件对象句柄同一个套接字关联起来,可用WSACreatEvent函数来创建一个事件对象句柄,并将重叠结构的hEventh字段分配给事件句柄,再使用重叠结构,调用一个Winsock函数即可,如WSASend或WSARecv。吉林大学软件学院吉林大学软件学院37l l一个重叠一个重叠一个重叠一个重叠I/OI/O请求最终完成后,应用程序要负责取回重请求最终完成后,应用
39、程序要负责取回重请求最终完成后,应用程序要负责取回重请求最终完成后,应用程序要负责取回重叠叠叠叠I/OI/O操作的结果。操作的结果。操作的结果。操作的结果。l在事件通知方法中,在事件通知方法中,Winsock会更改与一个会更改与一个WSAOVERLAPPED结构对应的一个事件对象的事件结构对应的一个事件对象的事件传信状态,将其从传信状态,将其从“未传信未传信”变成变成“已传信已传信”。l然后,调用然后,调用WSAWaitForMultipleEvents函数,判断一函数,判断一个重叠个重叠I/O调用在什么时候完成。调用在什么时候完成。lWSAWaitForMultipleEvents函数会等候
40、一段规定的时间,等待一个或多个事件对象进入“已传信”状态,该函数一次最多只能等待64个事件对象。吉林大学软件学院吉林大学软件学院38l获知一次重叠请求完成之后,接着需要调用获知一次重叠请求完成之后,接着需要调用WSAGetOverlappedResult(取得重叠结构)函数,(取得重叠结构)函数,判断重叠调用到底是成功,还是失败。判断重叠调用到底是成功,还是失败。l该函数定义如下:该函数定义如下:BOOL WSAGetOverlappedResult(SOCKET s;LPWSAOVERLAPPED lpoverlapped;LPDWORD lpcbTransfer;BOOL fWait;LP
41、DWORD lpdwFlags);39ls:用于指定在重叠操作开始时与之对应的套接字。用于指定在重叠操作开始时与之对应的套接字。llpOverlapped:是一个指针,对应于在重叠操作开始时,是一个指针,对应于在重叠操作开始时,指定的那个指定的那个WSAOVERLAPPED结构。结构。llpcbTransfer:也是一个指针,对应一个也是一个指针,对应一个DWORD(变量,(变量,负责接收一次重叠发送或接收操作实际传输的字节数。负责接收一次重叠发送或接收操作实际传输的字节数。lfWait:用于决定函数是否应该等待一次待决(未决)的重用于决定函数是否应该等待一次待决(未决)的重叠操作完成。叠操作
42、完成。l若设为TRUE,则除非操作完成,否则函数不会返回;l若设为FALSE,而且操作仍然处于“待决”状态,那么WSAGetOverlappedResult函数会返回FALSE值,同时返回一个WSA_IO_INCOMPLETE(I/O操作未完成)错误。l但就我们目前的情况来说,由于需要等候重叠操作的一个已传信事件完成,所以该参数无论采用什么设置,都没有任何效果。llpdwFlags:对应于一个指针,指向一个对应于一个指针,指向一个DWORD,负责,负责接收结果标志(假如原先的重叠调用是用接收结果标志(假如原先的重叠调用是用WSARecv或或WSARecvFrom函数发出的)。函数发出的)。吉林
43、大学软件学院吉林大学软件学院40l若若WSAGetOverlappedResult函数调用成功,返回值函数调用成功,返回值是是TRUE,意味着重叠,意味着重叠I/O操作已成功完成,而且由操作已成功完成,而且由lpcbTransfer参数指向的值已进行了更新。参数指向的值已进行了更新。l若返回值是若返回值是FALSE,那么可能是由下述任何一种原因,那么可能是由下述任何一种原因造成的:造成的:l重叠I/O操作仍处在“待决”状态;l重叠操作已经完成,但含有错误;l重叠操作的完成状态不可判决,因为在提供给WSAGetOverlappedResult函数的一个或多个参数中存在着错误。l失败后,由失败后,
44、由lpcbTransfer参数指向的值不会进行更新,参数指向的值不会进行更新,并且应用程序应调用并且应用程序应调用WSAGetLastError函数,调查到函数,调查到底是何种原因造成了调用失败。底是何种原因造成了调用失败。41l在下面的程序清单中,阐述如何编制一个简单的服务在下面的程序清单中,阐述如何编制一个简单的服务器应用,令其在一个套接字上对重叠器应用,令其在一个套接字上对重叠I/O操作进行管理,操作进行管理,程序完全利用了前述的程序完全利用了前述的事件通知机制事件通知机制事件通知机制事件通知机制。l对该程序采用的编程步骤总结如下:对该程序采用的编程步骤总结如下:1)创建一个套接字,开始
45、在指定端口上监听连接请求.2)接受一个进入的连接请求。3)为接受的套接字新建一个WSAOVERLAPPED结构,并为该结构分配一个事件对象句柄,同时将事件对象句柄分配给一个事件数组,以便稍后由WSAWaitForMultipleEvents函数使用。4)在套接字上投递一个异步WSARecv请求,指定参数为WSAOVERLAPPED结构。注意函数通常会以失败告终,返回SOCKET_ERROR错误状态WSA_IO_PENDING(I/O操作尚未完成)。425)使用步骤3)的事件数组,调用WSAWaitForMultipleEvents函数,并等待与重叠调用关联在一起的事件进入“已传信”状态(换言之
46、,等待那个事件的“触发”)。6)WSAWaitForMultipleEvents函数完成后,针对事件数组,调用WSAResetEvent(重设事件)函数,从而重设事件对象,并对完成的重叠请求进行处理。7)使用WSAGetOverlappedRESULT函数,判断重叠调用的返回状态是什么。8)在套接字上投递另一个重叠WSARecv请求。9)重复步骤5)8)。l这个例子极易扩展,提供对多个套接字的支持,方法这个例子极易扩展,提供对多个套接字的支持,方法是将代码的重叠是将代码的重叠I/O处理部分移至一个独立的线程内,处理部分移至一个独立的线程内,让主应用程序线程为附加的连接请求提供服务。让主应用程序
47、线程为附加的连接请求提供服务。吉林大学软件学院吉林大学软件学院432.完成例程完成例程l l应用程序用来管理完成的重叠应用程序用来管理完成的重叠应用程序用来管理完成的重叠应用程序用来管理完成的重叠I/OI/O请求的另一种方法请求的另一种方法请求的另一种方法请求的另一种方法.l实质是一些函数,开始时将其传递给一个重叠实质是一些函数,开始时将其传递给一个重叠I/O请求,请求,继而在一个重叠继而在一个重叠I/O请求完成时由系统调用。请求完成时由系统调用。l基本设计宗旨,是通过调用者的线程,为一个已完成基本设计宗旨,是通过调用者的线程,为一个已完成的的I/O请求提供服务。请求提供服务。l除此以外,应用
48、程序可通过完成例程,继续进行重叠除此以外,应用程序可通过完成例程,继续进行重叠I/O处理。处理。l如果希望用完成例程为重叠如果希望用完成例程为重叠I/O请求提供服务,在应用程序请求提供服务,在应用程序中必须为一个中必须为一个I/O定界定界Winsock函数,指定一个完成例程,函数,指定一个完成例程,同时指定一个同时指定一个WSAOVERLAPPED结构。结构。44l一个完成例程必须拥有下述函数原型:一个完成例程必须拥有下述函数原型:void CALLBACK CompletionROUTINE(DWORD dwError;DWORD cbTransferred;LPWSAOVERLAPPED
49、lpOverlapped;DWORD dwFlags);l用完成例程完成了一个重叠用完成例程完成了一个重叠I/O请求之后,参数中会包请求之后,参数中会包含下述信息:含下述信息:ldwError参数表明了一个重叠操作(由lpOverlapped指定)的完成状态是什么。lcbTransferred参数指定了在重叠操作期间,实际传输的字节量是多大。llpOverlapped参数指定的是传递到最初的I/O调用内的一个WSAOVERLAPPED结构。ldwFlags参数目前尚未使用,应设为0。吉林大学软件学院吉林大学软件学院45l l在用一个完成例程提交的重叠请求,与用一个事件对在用一个完成例程提交的重
50、叠请求,与用一个事件对在用一个完成例程提交的重叠请求,与用一个事件对在用一个完成例程提交的重叠请求,与用一个事件对象提交的重叠请求之间,存在一项非常重要的区别象提交的重叠请求之间,存在一项非常重要的区别象提交的重叠请求之间,存在一项非常重要的区别象提交的重叠请求之间,存在一项非常重要的区别:lWSAOVERLAPPED结构的hEvent字段并未使用,即不可将一个事件对象同重叠请求关联到一起。l用完成例程发出一个重叠用完成例程发出一个重叠I/O调用之后,一旦完成调用调用之后,一旦完成调用线程必须为完成例程提供服务,于是便要求将调用线线程必须为完成例程提供服务,于是便要求将调用线程置于一种程置于一