Socket网络编程学习之路 第五篇 ----winsock网络IO模型(2)之 重叠IO模型
来源:互联网 发布:郑州java程序员工资 编辑:程序博客网 时间:2024/03/28 17:31
需要注意的是,有两个方法可以用来管理重叠IO请求的完成情况(就是说接到重叠操作完成的通知):
1. 事件对象通知(event object notification)
2. 完成例程(completion routines) ,注意,这里并不是完成端口。
一.事件对象通知
既然是基于事件通知,就要求将Windows事件对象与WSAOVERLAPPED结构关联在一起(WSAOVERLAPPED结构中专门有对应的参数),,既然要使用重叠结构,我们常用的send, sendto, recv, recvfrom也都要被WSASend, WSASendto, WSARecv, WSARecvFrom替换掉了,它们的用法我后面会讲到,这里只需要注意一点,它们的参数中都有一个Overlapped参数,我们可以假设是把我们的WSARecv这样的操作操作“绑定”到这个重叠结构上,提交一个请求,其他的事情就交给重叠结构去操心,而其中重叠结构又要与Windows的事件对象“绑定”在一起,这样我们调用完WSARecv以后就可以“坐享其成”,等到重叠操作完成以后,自然会有与之对应的事件来通知我们操作完成,然后我们就可以来根据重叠操作的结果取得我们想要德数据了。
1.重叠IO模型的基础知识
(1)WSAOVERLAPPED结构
这个结构就是重叠模型里的核心了。
typedef struct _WSAOVERLAPPED
{
DWORD internal ;
DWORD internalHigh ;
DWORD offset ;
DWORD offsetHigh ;
WSAEVENT hEvent ;
} WSAOVERLAPPED , *LPWSAOVERLAPPED ;
我们需要把WSARecv投递到一个WSAOVERLAPPED结构上,我们也需要一个与这个结构绑定在一起的事件爱你来通知我们IO操作已经完成,下面介绍如何绑定事件:
WSAEVENT event ; // 定义事件
WSAOVERLAPPED AcceptOverlapped ; // 定义重叠结构
event = WSACreateEvent() ; // 建立一个事件对象句柄
ZeroMemory(&AcceptOverlapped , sizeof(WSAOVERLAPPED ) ) ;
AcceptOverlapped.hEvent = event ;
(2)WSARecv函数
在重叠模型中,这个函数是用来接收数据的函数,比recv函数多了一个重叠结构的参数外还有几个其他的参数,这个参数就是用来实现异步的关键。
int WSARecv(
SOCKET s ,
LPWSABUF lpBuffers , // 接收缓冲区,与recv函数不同,这里是一个WSABUF类型数组的首地址
DWORD dwBufferCount , // 接收缓冲区中数组的大小,即缓冲区的个数
LPDWORD lpNumOfBytesRecvd , // 返回函数调用所接收到的字节数
LPDWORD lpFlags ,
LPWSAOVERLAPPED lpOverlapped , // 绑定的重叠结构
LPWSAOVERLAPPED_Competition_Routine lpCompetitionRoutine // 完成例程中的参数
);
WSA_IO_PENDING : 最常见的返回值,这是说明我们的WSARecv操作成功了,但是I/O操作还没有完成,所以我们就需要绑定一个事件来通知我们操作何时完成 。
例子:
SOCKET s ;
WSABuf DataBuf ;
#define DATA_BUFFERSIZE 4096
char buf[DATA_BUFFERSIZE] ;
ZeroMemory( buf , DATA_BUFFERSIZE ) ;
DataBuf.len= DATA_BUFFERSIZE ;
DataBuf.buffer = buf ;
DWORD dwBufferCount = 1 , dwRecvCount = 0 , Flags = 0 ;
WSAOVERLAPPED AcceptOverlapped ; // 如果有处理多个操作,这里当然需要一个数组
WSAEVENT event ; // 如果处理多个操作,这里需要一个WSAEVENT的数组
event = WSACreateEvent() ; // 建立一个事件对象句柄
ZeroMemory(&AcceptOverlapped , sizeof(WSAOVERLAPPED ) ) ;
AcceptOverlapped.hEvent = event ; // 把事件句柄绑定到重叠结构上
WSARecv( s , &DataBuf , dwBufferCount , dwRecvBytes , Flags , &AcceptOverlapped , NULL );
int WaitForMutipleEvents(
DWORD dwCount , // 等待事件的个数
const WSAEVENT * lpEvent , // 事件数组的指针
BOOL bWait ,//如果设置为 TRUE,则事件数组中所有事件被传信的时候都会返回,FALSE则任何一个事件被传信函数都要返回
DWORD dwTimeOut // 超时事件,如果超时会返回WSA_WAIT_TIMEOUT DWORD dwAlertable // 这个在完成例程中会用到 ) ; 返回值: WSA_WAIT_TIMEOUT:在这个时候我们需要继续等待 WSA_WAIT_FAILED :出现错误WSAWaitForMultipleEvents函数只能支持由WSA_MAXIMUM_WAIT_EVENTS对象定义的一个最大值,是 64,就是说WSAWaitForMultipleEvents只能等待64个事件,如果想同时等待多于64个事件,就要 创建额外的工作者线程,就不得不去管理一个线程池,这一点就不如下一篇要讲到的完成例程模型了。
(4)GetOverlappedResult
既然我们使用函数WaitForMultipleEvents函数来等待IO的结果,那么我们也需要一个函数来检查等待的结果。
BOOL GetOverlappedResult(
SOCKET s ,
LPWSAOVERLAPPED lpOverlapped ,要查询那个重叠操作的结构的指针
LPWORD lpTransfer , // 实际接收到的字节数
BOOLdwWait
LPDOWD lpdwFlags // 接收结果的标志
) ;
唯一需要注意一下的就是如果WSAGetOverlappedResult完成以后,第三个参数返回是 0 ,则说明通信对方已经关闭连接,我们这边的SOCKET, Event之类的也就可以关闭了。
二.基于完成例程通知的重叠IO模型
基于事件通知的重叠IO模型,在使用WSARecv投递一个请求后,系统在完成后是通过事件来通知的,而完成例程是系统在完成以后是自己调用回调函函数,这就是唯一的区别。
从图中可以看到,服务器端存在一个明显的异步过程,也就是说我们把客户端连入的SOCKET与一个重叠结构绑定之后,便可以将通讯过程全权交给系统内部自己去帮我们调度处理了,我们在主线程中就可以去做其他的事情,边等候系统完成的通知就OK,这也就是完成例程高性能的原因所在。
如果还没有看明白,我们打个通俗易懂的比方,完成例程的处理过程,也就像我们告诉系统,说“我想要在网络上接收网络数据,你去帮我办一下”(投递WSARecv操作),“不过我并不知道网络数据合适到达,总之在接收到网络数据之后,你直接就调用我给你的这个函数(比如_CompletionProess),把他们保存到内存中或是显示到界面中等等,全权交给你处理了”,于是乎,系统在接收到网络数据之后,一方面系统会给我们一个通知,另外同时系统也会自动调用我们事先准备好的回调函数,就不需要我们自己操心了。
完成例程中的回调函数的原型:
Void CALLBACK _CompletionRoutineFunc(
DWORD dwError, // 标志咱们投递的重叠操作,比如WSARecv,完成的状态是什么
DWORD cbTransferred, // 指明了在重叠操作期间,实际传输的字节量是多大
LPWSAOVERLAPPED lpOverlapped, // 参数指明传递到最初的IO调用内的一个重叠 结构
DWORD dwFlags // 返回操作结束时可能用的标志(一般没用)
);
还有一点需要重点提一下的是,因为我们需要给系统提供一个如上面定义的那样的回调函数,以便系统在完成了网络操作后自动调用,这里就需要提一下究竟是如何把这个函数与系统内部绑定的呢?如下所示,在WSARecv函数中是这样绑定的。
int WSARecv(
SOCKET s, // 当然是投递这个操作的套接字
LPWSABUF lpBuffers, // 接收缓冲区,与Recv函数不同
// 这里需要一个由WSABUF结构构成的数组
DWORD dwBufferCount, // 数组中WSABUF结构的数量,设置为1即可
LPDWORD lpNumberOfBytesRecvd, // 如果接收操作立即完成,这里会返回函数调用
// 所接收到的字节数
LPDWORD lpFlags, // 这里设置为0 即可
LPWSAOVERLAPPED lpOverlapped, // “绑定”的重叠结构
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
// 我们的完成例程函数的指针
);
举个例子:
SOCKET s;
WSABUF DataBuf; // 定义WSABUF结构的缓冲区
// 初始化一下DataBuf
#define DATA_BUFSIZE 4096
char buffer[DATA_BUFSIZE];
ZeroMemory(buffer, DATA_BUFSIZE);
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = buffer;
DWORD dwBufferCount = 1, dwRecvBytes = 0, Flags = 0;
// 建立需要的重叠结构,每个连入的SOCKET上的每一个重叠操作都得绑定一个
WSAOVERLAPPED AcceptOverlapped ;// 如果要处理多个操作,这里当然需要一个
// WSAOVERLAPPED数组
ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));
// 作了这么多工作,终于可以使用WSARecv来把我们的完成例程函数绑定上了
// 当然,假设我们的_CompletionRoutine函数已经定义好了
WSARecv(s, &DataBuf, dwBufferCount, &dwRecvBytes,
&Flags, &AcceptOverlapped, _CompletionRoutine);
关于例子,后续博文会给出相关的Demo。
- Socket网络编程学习之路 第五篇 ----winsock网络IO模型(2)之 重叠IO模型
- windows Socket编程之重叠IO模型
- socket网络编程之路 第四篇 ------winsock网络编程模型(1)之概述
- 网络编程五种IO模型之重叠IO模型-完成例程
- 网络编程五种IO模型之重叠IO模型-事件驱动
- 【Windows网络编程】重叠IO网络模型
- 网络编程学习:io模型之io多路复用
- winsock重叠IO模型
- winsock IO 模型---重叠IO之事件通知 example code
- WinSock之CAsyncSocket模型与重叠IO模型(1)
- Winsock 网络编程 Socket模型之Select模型
- Winsock 网络编程 Socket模型之WSAAsyncSelect模型
- Winsock 网络编程 Socket模型之WSAEventSelect模型
- Winsock 网络编程 Socket模型之Overlapped模型
- Winsock 网络编程 Socket模型之Completion模型
- 关于重叠IO网络编程模型的学习!
- WinSock IO模型---重叠模型
- 网络事件模型---重叠IO
- 查找算法之——二分查找
- jQuery Easyui Validatebox rules的常用扩展
- 通过WMI接口,修改VisualSVN用户密码
- c# 数组 数组列表 列表 foreach
- NSLog效率低下的原因及尝试lldb断点打印Log
- Socket网络编程学习之路 第五篇 ----winsock网络IO模型(2)之 重叠IO模型
- 第十四周工作日志
- 数据挖掘:数据挖掘Apriori算法
- jquery控制select的值,选中状态
- 重写类的equals方法
- oj C++继承(改错题)
- java中 Random类的用法
- 【Leetcode】Sort List
- 鱼类小志