已阅读5页,还剩3页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Socket编程模型之事件选择模型一原理与关键函数Winsock提供了另一个有用的异步I/O模型。和WSAAsyncSelect模型类似的是,它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知。对于表1总结的、由WSAAsyncSelect模型采用的网络事件来说,它们均可原封不动地移植到新模型。在用新模型开发的应用程序中,也能接收和处理所有那些事件。该模型最主要的差别在于网络事件会投递至一个事件对象句柄,而非投递至一个窗口例程。跟WSAAsyncSelect类似,但是不是通过消息实现,而是通过事件对象。因为是基于select实现,一个线程也只能管理64个socket。事件选择模型是基于消息的。它允许程序通过Socket,接收以事件为基础的网络事件通知。事件选择模型相关函数主要有4个,第一个是:cpp view plain copy 在CODE上查看代码片派生到我的代码片WSAEVENT WSACreatEvent(void) 它用来创建事件对象。如果函数成功,则返回值即是事件对象的句柄。如果函数失败,返回WSA_INVALID_EVENT。应用程序可通过调用WSAGetLastError()函数获取进一步的错误信息。主要的错误代码有:cpp view plain copy 在CODE上查看代码片派生到我的代码片WSANOTINITIALISED /在调用本API之前应成功调用WSAStartup()。 WSAENETDOWN /网络子系统失效。 WSA_NOT_ENOUGH_MEMORY /无足够内存创建事件对象。 第2个是:cpp view plain copy 在CODE上查看代码片派生到我的代码片int WSAEventSelect(SOCKET s, WSAEVENT hEventObject,long lNetworkEvents) WSAEventSelect模型是WindowsSockets提供的一个有用异步I/O模型。该模型允许在一个或者多个套接字上接收以事件为基础的网络事件通知。Windows Sockets应用程序在创建套接字后,调用WSAEventSelect()函数,将一个事件对象与网络事件集合关联在一起。当网络事件发生时,应用程序以事件的形式接收网络事件通知。WSAEventSelect创建的事件拥有两种工作状态,以及两种工作模式。其中,两种工作状态分别是“已传信”(signaled)和“未传信”(non signaled)。工作模式则包括“人工重设”(manual reset)和“自动重设”(auto reset)。WSAEventSelect最开始在一种未传信的工作状态中,并用一种人工重设模式,来创建事件句柄。随着网络事件触发了与一个套接字关联在一起的事件对象,工作状态便会从“未传信”转变成“已传信”。由于事件对象是在一种人工重设模式中创建的,所以在完成了一个I/O请求的处理之后,我们的应用程序需要负责将工作状态从已传信更改为未传信。要做到这一点,可调用WSAResetEvent函数,对它的定义如下:BOOL WSAResetEvent(WSAEVENT hEvent);唯一的参数是前面用WSACreateEvent函数创建的事件对象句柄,成功返回TRUE,失败返回FALSE。当应用程序完成了对一个事件对象的处理后,应调用BOOL WSACloseEvent(WSAEVENT hEvent);函数释放由hEvent句柄占用的系统资源。成功返回TRUE,失败返回FALSE。第3个是:cpp view plain copy 在CODE上查看代码片派生到我的代码片DWORD WSAAPI WSAWaitForMultipleEvents( DWORD cEvents,const WSAEVENT FAR * lphEvents, BOOL fWaitAll, DWORD dwTimeout, BOOL fAlertable ); 只要指定事件对象中的一个或全部处于有信号状态,或者超时间隔到,则返回。cEvents:指出lphEvents所指数组中事件对象句柄的数目。事件对象句柄的最大值为WSA_MAXIMUM_WAIT_EVENTS。lphEvents:指向一个事件对象句柄数组的指针。fWaitAll:指定等待类型。若为真TRUE,则当lphEvents数组中的所有事件对象同时有信号时,函数返回。若为假FALSE,则当任意一个事件对象有信号时函数即返回。在后一种情况下,返回值指出是哪一个事件对象造成函数返回。dwTimeout:指定超时时间间隔(以毫秒计)。当超时间隔到,函数即返回,不论fWaitAll参数所指定的条件是否满足。如果dwTimeout为零,则函数测试指定的时间对象的状态,并立即返回。如果dwTimeout是WSA_INFINITE,则函数的超时间隔永远不会到。fAlertable:指定当系统将一个输入/输出完成例程放入队列以供执行时,函数是否返回。若为真TRUE,则函数返回且执行完成例程。若为假FALSE,函数不返回,不执行完成例程。请注意在Win16中忽略该参数。如果函数成功,返回值指出造成函数返回的事件对象。(这一句有问题),应该改成:如果事件数组中有某一个事件被传信了,函数会返回这个事件的索引值,但是这个索引值需要减去预定义值 WSA_WAIT_EVENT_0才是这个事件在事件数组中的位置。如果函数失败,返回值为WSA_WAIT_FAILED。可调用WSAGetLastError()来获取进一步的错误信息。错误代码:cpp view plain copy 在CODE上查看代码片派生到我的代码片WSANOTINITIALISED /在调用本API之前应成功调用WSAStartup()。 WSAENETDOWN /网络子系统失效。 WSA_NOT_ENOUGH_MEMORY /无足够内存完成该操作。 WSA_INVALID_HANDLE /lphEvents数组中的一个或多个值不是合法的事件对象句柄。 WSA_INVALID_PARAMETER /cEvents参数未包含合法的句柄数目。 第4个函数:cpp view plain copy 在CODE上查看代码片派生到我的代码片int WSAAPI WSAEnumNetworkEvents ( SOCKET s, WSAEVENT hEventObject, LPWSANETWORKEVENTS lpNetworkEvents, LPINT lpiCount); 检测所指定的套接口上网络事件的发生。s:标识套接口的描述字。hEventObject:(可选)句柄,用于标识需要复位的相应事件对象。lpNetworkEvents:一个WSANETWORKEVENTS结构的数组,每一个元素记录了一个网络事件和相应的错误代码。lpiCount:数组中的元素数目。在返回时,本参数表示数组中的实际元素数目;如果返回值是WSAENOBUFS,则表示为获取所有网络事件所需的元素数目。如果操作成功则返回0。否则的话,将返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()来获取相应的错误代码。错误代码:cpp view plain copy 在CODE上查看代码片派生到我的代码片WSANOTINITIALISED /在调用本API之前应成功调用WSAStartup()。 WSAENETDOWN /网络子系统失效。 WSAEINVAL /参数中有非法值。 WSAEINPROGRESS /一个阻塞的WinSock调用正在进行中,或者服务提供者仍在处理一个回调函数WSAENOBUFS 所提供的缓冲区太小。 二完整实例与运行效果示例仍然使用反射式服务端与反射式客户端。关于反射式客户端的代码请参见:/caoshiying/article/details/52550761第三章。关于本示例程序使用的公共组件请参见/caoshiying/article/details/52550761第四章。可以用类向导创建一个event_server_manager类型,头文件如下:cpp view plain copy 在CODE上查看代码片派生到我的代码片#pragma once #include #include #include class event_server_manager: protected iserver_manager private: WSADATA wsa; int iclient_count; int iaddr_size; int iport; SOCKET server; SOCKET clientsFD_SETSIZE; WSAEVENT meventsFD_SETSIZE; common_callback callback; BOOL brunning; private: void cleanup(int index); protected: bool accept_by_crt(); bool accept_by_winapi(); void receive(); public: void shutdown(); void start_accept_by_crt(); void start_accept_by_winapi(); void start_receive(); public: event_server_manager(); virtual event_server_manager(); ; 实现文件如下:cpp view plain copy 在CODE上查看代码片派生到我的代码片#include event_server_manager.h #include #include #include #include event_server_manager:event_server_manager() WSAStartup(MAKEWORD(2, 2), &wsa); iclient_count = 0; iport = 5150; iaddr_size = sizeof(SOCKADDR_IN); brunning = FALSE; callback.set_manager(this); event_server_manager:event_server_manager() bool event_server_manager:accept_by_crt() SOCKET conn_socket; SOCKADDR_IN local; SOCKADDR_IN conn_addr; int iret = 0; server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); local.sin_addr.S_un.S_addr = htonl(INADDR_ANY); local.sin_family = AF_INET; local.sin_port = htons(iport); do iret = bind(server, (struct sockaddr*)&local, iaddr_size); if (iret = 0) break; iport+; local.sin_port = htons(iport); while (iret = SOCKET_ERROR); listen(server, 3); printf_s(服务已经启动,监听端口是:%dn, iport); while (brunning) conn_socket = accept(server, (struct sockaddr*)&conn_addr, &iaddr_size); if (conn_socket = INVALID_SOCKET) printf_s(拒绝一个连接。n); continue; printf_s(新连接%s:%d。n, inet_ntoa(conn_addr.sin_addr), ntohs(conn_addr.sin_port); clientsiclient_count = conn_socket; meventsiclient_count = WSACreateEvent(); WSAEventSelect(conn_socket, meventsiclient_count, FD_ALL_EVENTS); iclient_count+; return true; bool event_server_manager:accept_by_winapi() return true; void event_server_manager:receive() DWORD iret = 0; int index = 0; WSANETWORKEVENTS nevent; char message1024 = 0 ; while (brunning) iret = WSAWaitForMultipleEvents(iclient_count, mevents, FALSE, 1000, FALSE); if (iret = WSA_WAIT_FAILED | iret = WSA_WAIT_TIMEOUT) continue; index = iret - WSA_WAIT_EVENT_0; WSAEnumNetworkEvents(clientsindex, meventsindex, &nevent); if (nevent.lNetworkEvents&FD_READ) iret = recv(clientsindex, message, 1024, 0); if (iret = 0 | (iret = SOCKET_ERROR&WSAGetLastError() = WSAECONNRESET) cleanup(index); else messageiret = 0; send(clientsindex, message, iret, 0); if (nevent.lNetworkEvents&FD_CLOSE) cleanup(index); void event_server_manager:cleanup(int index) SOCKADDR_IN client; assert(index iclient_count); getpeername(clientsindex, (struct sockaddr*)&client, &iaddr_size); printf_s(客户端%s:%d断开连接。n, inet_ntoa(client.sin_addr), ntohs(client.sin_port); closesocket(clientsindex); WSACloseEvent(meventsindex); if (index iclient_count - 1) clientsindex = clientsiclient_count - 1; meventsindex = meventsiclient_count - 1; clientsiclient_count - 1 = 0; mevent
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年室内硬装设计培训师高级真题及答案
- 纳米技术在提高橡胶材料耐磨性方面的应用-洞察及研究
- 短视频平台营销策略与用户留存率提升的策略分析-洞察及研究
- 煤炭开采信息化标准-洞察及研究
- 2025年职业培训与人力资源发展项目可行性研究报告
- 2025年远程办公技术平台建设项目可行性研究报告
- 2025年广电网络宽带建设可行性研究报告
- 2025年光伏发电项目投资回报分析可行性研究报告
- 2025年新型物流仓储设施建设项目可行性研究报告
- 2025年现代服务业升级项目可行性研究报告
- 2025年宠物产业综合体项目可行性研究报告及总结分析
- 2025年4月临床药物治疗学复习题(含答案)
- 四川省凉山2025年数学高一第一学期期末监测试题含解析
- 2025年在线教育平台开发合同协议
- 2025河北邯郸市产业投资集团有限公司下属企业专业人才招聘78人笔试考试参考试题及答案解析
- 2025北京证券交易所全国中小企业股份转让系统有限责任公司校园招聘考试笔试备考题库及答案解析
- 2025年感动中国十大人物适用主题及素材运用励志学子庞众望:“个人选择与家国命运”作文导写高考语文作文热点新闻素材速记快用
- 医院用电消防安全培训课件
- 2025年秋人教版小学五年级数学上册竞赛测试卷(含答案解析)
- 2025上半年幼儿教资笔试真题及答案,幼师资格证考试
- 第23课《富贵不能淫》课件 2025-2026学年统编版语文八年级上册
评论
0/150
提交评论