网络通信编程技术3.ppt_第1页
网络通信编程技术3.ppt_第2页
网络通信编程技术3.ppt_第3页
网络通信编程技术3.ppt_第4页
网络通信编程技术3.ppt_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第3章Windows套接字I O模型 阻塞 blocking 模型选择 select 模型WSAAsyncSelect模型WSAEventSelect模型重叠 overlapped 模型完成端口 completionport 模型 3 1 1阻塞模式 套接字创建时 默认工作在阻塞模式下 例如 对recv函数的调用会使程序进入等待状态 直到接收到数据才返回 第2章的示例程序都是这种情况 大多数Winsock程序设计者都是从阻塞套接字模式开始学习的 因为这是最容易和最直接的方式 处理阻塞模式套接字的应用程序使用的程序框架便是阻塞模型 此模型是非常容易理解的 阻塞套接字的好处是使用简单 但是当需要处理多个套接字连接时 就必须创建多个线程 即典型的一个连接使用一个线程的问题 这给编程带来了许多不便 所以实际开发中使用最多的还是下面要讲述的非阻塞模式 3 1 2非阻塞模式 非阻塞套接字使用起来比较复杂 但是却有许多优点 应用程序可以调用ioctlsocket函数显式地让套接字工作在非阻塞模式下 如下代码所示 u longul 1 SOCKETs socket AF INET SOCK STREAM 0 ioctlsocket s FIONBIO u long 一旦套接字被置于非阻塞模式 处理发送和接收数据或者管理连接的Winsock调用将会立即返回 大多少情况下 调用失败的出错代码是WSAEWOULDBLOCK 这意味着请求的操作在调用期间没有完成 例如 如果系统输入缓冲区中没有待处理的数据 那么对recv的调用将返回WSAEWOULDBLOCK 通常 要对相同函数调用多次 直到它返回成功为止 非阻塞调用经常以WSAEWOULDBLOCK出错代码失败 所以将套接字设置为非阻塞之后 关键的问题在于如何确定套接字什么时候可读 可写 也就是说确定网络事件何时发生 如果需要自己不断调用函数去测试的话 程序的性能势必会受到影响 解决的办法就是使用Windows提供的不同的I O模型 3 2选择 select 模型 select模型是一个广泛在Winsock中使用的I O模型 称它为select模型 是因为它主要是使用select函数来管理I O的 这个模式的设计源于UNIX系统 目的是允许那些想要避免在套接字调用上阻塞的应用程序有能力管理多个套接字 3 2 1select函数 select函数可以确定一个或者多个套接字的状态 如果套接字上没有网络事件发生 便进入等待状态 以便执行同步I O 函数定义如下 intselect intnfds 忽略 仅是为了与Berkeley套接字兼容fd set readfds 指向一个套接字集合 用来检查其可读性fd set writefds 指向一个套接字集合 用来检查其可写性fd set exceptfds 指向一个套接字集合 用来检查错误conststructtimeval timeout 指定此函数等待的最长时间 如果为NULL 则最长时间为无限大 函数调用成功 返回发生网络事件的所有套接字数量的总和 如果超过了时间限制 返回0 失败则返回SOCKET ERROR 1 套接字集合fd set结构可以把多个套接字连在一起 形成一个套接字集合 select函数可以测试这个集合中哪些套接字有事件发生 下面是这个结构在WINSOCK2 h中的定义 3 2 1select函数 1 套接字集合fd set结构可以把多个套接字连在一起 形成一个套接字集合 select函数可以测试这个集合中哪些套接字有事件发生 下面是这个结构在WINSOCK2 h中的定义 typedefstructfd set u intfd count 下面数组的大小SOCKETfd array FD SETSIZE 套接字句柄数组 fd set 下面是WINSOCK定义的4个操作fd set套接字集合的宏 3 2 1select函数 FD ZERO set 初始化set为空集合 集合在使用前应该总是清空zFD CLR s set 从set移除套接字szFD ISSET s set 检查s是不是set的成员 如果是返回TRUEzFD SET s set 添加套接字到集合 3 2 1select函数 网络事件传递给select函数的3个fd set结构中 一个是为了检查可读性 readfds 一个是为了检查可写性 writefds 另一个是为了检查错误 exceptfds select函数返回之后 如果有下列事件发生 其对应的套接字就会被标识 3 2 1select函数 下面的例子示例了select函数的用法 程序运行之后 在4567端口监听 接受客户端连接请求 打印出接收到的数据 大家可以看到采用select模型之后 即便是在单个线程中 也可以管理多个套接字 具体编程流程如下 1 初始化套接字集合fdSocket 向这个集合添加监听套接字句柄 2 将fdSocket集合的拷贝fdRead传递给select函数 当有事件发生时 select函数移除fdRead集合中没有未决I O操作的套接字句柄 然后返回 3 比较原来fdSocket集合与select处理过的fdRead集合 确定哪些套接字有未决I O 并进一步处理这些I O 4 回到第2步继续进行选择处理 3 2 1select函数 实际例程 3 3WSAAsyncSelect模型 WSAAsyncSelect模型允许应用程序以Windows消息的形式接收网络事件通知 这个模型是为了适应Windows的消息驱动环境而设置的 现在许多对性能要求不高的网络应用程序都采用WSAAsyncSelect模型 MFC MicrosoftFoundationClass Microsoft基础类库 中的CSocket类也使用了它 3 3WSAAsyncSelect模型 3 3 1消息通知和WSAAsyncSelect函数WSAAsyncSelect函数自动把套接字设为非阻塞模式 并且为套接字绑定一个窗口句柄 当有网络事件发生时 便向这个窗口发送消息 函数用法如下 intWSAAsyncSelect SOCKETs 需要设置的套接字句柄HWNDhWnd 指定一个窗口句柄 套接字的通知消息将被发送到与其对应的窗口过程中u intwMsg 网络事件到来时接收到的消息ID 可以在WM USER以上的数值中任意选择一个用做ID longlEvent 指定哪些通知码需要发送 3 3WSAAsyncSelect模型 最后一个参数lEvent指定了要发送的通知码 可以是如下取值的组合 zFD READ套接字接收到对方发送过来的数据包 表明这时可以去读套接字了zFD WRITE数据缓冲区满后再次变空时 WinSock接口通过该通知码通知应用程序 表示可以继续发送数据了 短时间内发送数据过多 便会造成数据缓冲区变满 zFD ACCEPT监听中的套接字检测到有连接进入zFD CONNECT如果用套接字去连接对方的主机 当连接动作完成以后会接收到这个通知码zFD CLOSE检测到套接字对应的连接被关闭例如 在监听套接字上可以这样调用WSAAsyncSelect函数 WSAAsyncSelect sListen hWnd WM SOCKET FD ACCEPT FD CLOSE WM SOCKET为自定义消息上述代码将套接字sListen设为窗口通知消息类型 WM SOCKET为自定义网络通知消息 FD CLOSE FD ACCEPT指定了sListen套接字只接收FD CLOSE和FD ACCEPT通知消息 当有客户连接或套接字关闭时 Winsock接口将向指定的窗口发送WM SOCKET消息 3 3WSAAsyncSelect模型 最后一个参数lEvent指定了要发送的通知码 可以是如下取值的组合 zFD READ套接字接收到对方发送过来的数据包 表明这时可以去读套接字了zFD WRITE数据缓冲区满后再次变空时 WinSock接口通过该通知码通知应用程序 表示可以继续发送数据了 短时间内发送数据过多 便会造成数据缓冲区变满 zFD ACCEPT监听中的套接字检测到有连接进入zFD CONNECT如果用套接字去连接对方的主机 当连接动作完成以后会接收到这个通知码zFD CLOSE检测到套接字对应的连接被关闭例如 在监听套接字上可以这样调用WSAAsyncSelect函数 WSAAsyncSelect sListen hWnd WM SOCKET FD ACCEPT FD CLOSE WM SOCKET为自定义消息上述代码将套接字sListen设为窗口通知消息类型 WM SOCKET为自定义网络通知消息 FD CLOSE FD ACCEPT指定了sListen套接字只接收FD CLOSE和FD ACCEPT通知消息 当有客户连接或套接字关闭时 Winsock接口将向指定的窗口发送WM SOCKET消息 3 3WSAAsyncSelect模型 成功调用WSAAsyncSelect之后 应用程序便开始以Windows消息的形式在窗口函数接收网络事件通知 下面是窗口函数的定义 LRESULTCALLBACKWindowProc HWNDhWnd UINTuMsg WPARAMwParam LPARAMlParam wParam参数指定了发生网络事件的套接字句柄 lParam参数的低字位指定了发生的网络事件 高字位包含了任何可能出现的错误代码 可以使用宏WSAGETSELECTERROR和WSAGETSELECTEVENT将这些信息取出 这两个宏定义在Winsock2 h文件中 defineWSAGETSELECTERROR lParam HIWORD lParam 高字为出错代码 defineWSAGETSELECTEVENT lParam LOWORD lParam 低字为通知码如果没有错误发生 出错代码为0 程序可以继续检查通知码 以确定发生的网络事件 3 3WSAAsyncSelect模型 3 3 2应用举例 3 4WSAEventSelect模型 Winsock提供了另一种有用的异步事件通知I O模型 WSAEventSelect模型 这个模型与WSAAsyncSelect模型类似 允许应用程序在一个或者多个套接字上接收基于事件的网络通知 它与WSAAsyncSelect模型类似是因为它也接收FD XXX类型的网络事件 不过并不是依靠Windows的消息驱动机制 而是经由事件对象句柄通知 3 4 1WSAEventSelect函数 使用这个模型的基本思路是为感兴趣的一组网络事件创建一个事件对象 再调用WSAEventSelect函数将网络事件和事件对象关联起来 当网络事件发生时 Winsock使相应的事件对象受信 在事件对象上的等待函数就会返回 之后 调用WSAEnumNetworkEvents函数便可获取到底发生了什么网络事件 Winsock中创建事件对象的函数是WSACreateEvent 定义如下 WSAEVENTWSACreateEvent void 返回一个手工重置的事件对象句柄创建事件对象之后 必须调用WSAEventSelect函数将指定的一组网络事件与它关联在一起 函数用法如下 intWSAEventSelect SOCKETs 套接字句柄WSAEVENThEventObject 事件对象句柄longlNetworkEvents 感兴趣的FD XXX网络事件的组合 网络事件与事件对象关联之后 应用程序便可以在事件对象上等待了 Winsock提供了WSAWaitForMultipleEvents函数在一个或多个事件对象上等待 当所等待的事件对象受信 或者指定的时间过去时 此函数返回 WSAWaitForMultipleEvents函数用法如下 DWORDWSAWaitForMultipleEvents DWORDcEvents 指定下面lphEvents所指的数组中事件对象句柄的个数constWSAEVENT lphEvents 指向一个事件对象句柄数组BOOLfWaitAll 指定是否等待所有事件对象都变成受信状态 3 4 1WSAEventSelect函数 DWORDdwTimeout 指定要等待的时间 WSA INFINITE为无穷大BOOLfAlertable 在使用WSAEventSelect模型时可以忽略 应设为FALSE WSAWaitForMultipleEvents最多支持WSA MAXIMUM WAIT EVENTS个对象 WSA MAXIMUM WAIT EVENTS被定义为64 因此 这个I O模型在一个线程中同一时间最多能支持64个套接字 如果需要使用这个模型管理更多套接字 就需要创建额外的工作线程了 WSAWaitForMultipleEvents函数会等待网络事件的发生 如果过了指定的时间 函数返回WSA WAIT TIMEOUT 如果在指定时间内有网络事件发生 函数的返回值会指明是哪一个事件对象促使函数返回的 函数调用失败时返回值是WSA WAIT FAILED 也可以将dwTimeout的值设为0 这时函数测试指定事件对象的状态 并立即返回 通过函数的返回值便可知道事件对象是否受信 注意 将fWaitAll参数设为FALSE以后 如果同时有几个事件对象受信 WSAWaitForMultipleEvents函数的返回值也仅能指明一个 就是句柄数组中最前面的那个 如果指明的这个事件对象总有网络时间发生 那么后面其他事件对象所关联的网络事件就得不到处理了 解决办法是 WSAWaitForMultipleEvents函数返回后 对每个事件都再次调用WSAWaitForMultipleEvents函数 以便确定其状态 具体过程请参考后面的实例代码 3 4 1WSAEventSelect函数 一旦事件对象受信 那么找到与之对应的套接字 然后调用WSAEnumNetworkEvents函数即可查看发生了什么网络事件 函数用法如下 intWSAEnumNetworkEvents SOCKETs 套接字句柄WSAEVENThEventObject 对应的事件对象句柄 如果提供了此参数 本函数会重置这个事件对象的状态LPWSANETWORKEVENTSlpNetworkEvents 指向一个WSANETWORKEVENTS结构 最后一个参数用来取得在套接字上发生的网络事件和相关的出错代码 其结构定义如下 typedefstruct WSANETWORKEVENTS longlNetworkEvents 指定已发生的网络事件 如FD ACCEPT FD READ等 intiErrorCode FD MAX EVENTS 与lNetworkEvents相关的出错代码 WSANETWORKEVENTS LPWSANETWORKEVENTS iErrorCode参数是一个数组 数组的每个成员对应着一个网络事件的出错代码 可以用预定义标识FD READ BIT FD WRITE BIT等来索引FD READ FD WRITE等事件发生时的出错代码 如下面代码片段所示 if event lNetworkEvents FD READ 处理FD READ通知消息 3 4 2应用举例 下面使用WSAEventSelect模型重写上节的TCP服务器例子 使用WSAEventSelect模型编程的基本步骤如下 1 创建一个事件句柄表和一个对应的套接字句柄表 2 每创建一个套接字 就创建一个事件对象 把它们的句柄分别放入上面的两个表中 并调用WSAEventSelect添加它们的关联 3 调用WSAWaitForMultipleEvents在所有事件对象上等待 此函数返回后 我们对事件句柄表中的每个事件调用WSAWaitForMultipleEvents函数 以便确认在哪些套接字上发生了网络事件 4 处理发生的网络事件 继续在事件对象上等待 下面是程序代码 3 4 3基于WSAEventSelect模型的服务器设计 这个例子的功能和上一小节的一样 不同的是它使用了线程池 可以处理大量的客户I O请求 这个例子稍微复杂 但却是后面设计功能更强大的服务器程序的基础 设计的总体思路比较简单 程序的主线程负责监听客户端的连接请求 接受到新连接之后 将新套接字安排给工作线程处理I O 每个工作线程最多处理64个套接字 如果再有新的套接字 就再创建新的工作线程 下面先讨论两个重要的结构 然后再讲述具体的实现代码 1 套接字对象程序用下面的SOCKET OBJ结构来记录每个客户端套接字的信息 typedefstruct SOCKET OBJ 3 4 3基于WSAEventSelect模型的服务器设计 SOCKETs 套接字句柄HANDLEevent 与此套接字相关联的事件对象句柄sockaddr inaddrRemote 客户端地址信息 SOCKET OBJ pNext 指向下一个SOCKET OBJ对象 以连成一个表 SOCKET OBJ PSOCKET OBJ 服务器程序每接受到一个新的连接 便为新连接申请一个SOCKET OBJ结构 初始化该结构的成员 当连接关闭或者出错时 再释放内存空间 下面的GetSocketObj和FreeSocketObj函数分别用于申请和释放一个SOCKET OBJ对象 PSOCKET OBJGetSocketObj SOCKETs 申请一个套接字对象 初始化它的成员 PSOCKET OBJpSocket PSOCKET OBJ GlobalAlloc GPTR sizeof SOCKET OBJ if pSocket NULL pSocket s s pSocket event WSACreateEvent returnpSocket voidFreeSocketObj PSOCKET OBJpSocket 释放一个套接字对象 CloseHandle pSocket event if pSocket s INVALID SOCKET closesocket pSocket s GlobalFree pSocket 3 4 3基于WSAEventSelect模型的服务器设计 2 线程对象程序用下面的THREAD OBJ结构

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论