IOCP的几点开发心得
来源:互联网 发布:Linux测试telnet 编辑:程序博客网 时间:2024/05/16 06:49
IOCP以其高效的性能受到服务器开发者的青睐,本人有幸在当前的项目中使用了该异步模型,修改调试之余,总结出开发过程中的经验若干,供大家借鉴。
首先是需要注意的是OVERLAPPED结构。想必该结构大多数人都是自定义新的结构体,将OVERLAPPED成员放置在第一位,然后后置其他成员。
在 函数 WSASend, WSARecv, PostQueuedCompletionStatus 以及GetQueuedCompletionStatus 中都有LPOVERLAPPED的参数,其中在前面三个函数中是输入参数,后面一个函数中是输出参数。对于输入参数可以传入强制转换的自定义结构体指针 (不需要取地址),也可以传入自定义结构体中OVERLAPPED成员的地址(需要取地址);对于输出参数,将要传出的是前三个函数中输入参数的地址。在 开发过程中,对于该结构地址的操作需要细心。
形如以下的代码都是正确的:
WSASend(pClientData->IoSocket, &(pPerIoData->WsaSendDataBuff), 1, &dwSendBytes, 0, &(pPerIoData->overlaped), NULL);
GetQueuedCompletionStatus(pThis->m_hIOCP, &dwBytesTransferred,(LPDWORD)&pPerHandleData, (LPOVERLAPPED *)&pPerIoData, INFINITE);
其次需要注意的是PostQueuedCompletionStatus 函数。该函数向IOCP发送三个参数(DWORD dwNumberOfBytesTransferred, ULONG_PTR dwCompletionKey, LPOVERLAPPED lpOverlapped),GetQueuedCompletionStatus 函数将接收到这三个参数。IOCP将不会对这三个参数做任何操作。
在 实际应用中,该函数一般用于控制IOCP接收线程的退出。其实,该函数的用法远不止于此,它还可以作为消息来使用。通过定义特定的 dwNumberOfBytesTransferred消息值,然后通过PostQueuedCompletionStatus函数向IOCP中POST 该消息,GetQueuedCompletionStatus 函数就可以捕获该消息。自定义的dwNumberOfBytesTransferred消息值一定要大于接收BUFFER和发送BUFFER的最大长度, 否则作为消息就没有意义了。
还有一个需要注意的是WSARecv函数。在IOCP中多次调用该函数是有后果的,严重的会导致接收缓 冲区被塞满,就算没有塞满接收缓冲区,如果客户端意外断开连接,GetQueuedCompletionStatus 函数会接到与调用次数一样多次数的返回错误,想必大家一定都不希望这些情况发生。要避免这种问题一定要谨慎的调用WSARecv函数,最好在 GetQueuedCompletionStatus 函数接收到数据后再考虑再次调用WSARecv。
今天又测出一个潜在的BUG,先贴代码:
首先是定义:
{
IoRecv, //WSARecv
IoSend, //WSASend
IoQuit
}IO_OPERATION, *PIO_OPERATION;
typedef struct _PER_IO_CONTEXT
{
WSAOVERLAPPED ol;
WSABUF WsaRecvDataBuff;
WSABUF WsaSendDataBuff;
char strRecvBuffer[DATA_MAX_BUFFERSIZE]; //接收BUFFER
char strSendBuffer[DATA_MAX_BUFFERSIZE]; //发送BUFFER
IO_OPERATION IoType;
}PER_IO_CONTEXT, *LPPER_IO_CONTEXT;
这里的IO_OPERATION定义了三种类型,分别表示接收、发送和退出,GetQueuedCompletionStatus函数在接收到消息时,可以通过检测IoType的类型来判断IOCP刚刚完成的操作是接收操作还是发送操作亦或是退出操作。
在 一次操作中(比如接收到数据后的操作),先后调用WSASend和WSARecv,来实现发送数据,然后继续Recv的动作,这样做可行吗?答案是否定 的。分析:调用WSASend之前,设置IoType为IoSend,标志本次操作是发送操作;然后在调用WSARecv前,设置IoType为 IoRecv,标志本次操作是接收操作。IOCP在处理消息队列时,首先应该接收到的是发送操作,由于IoType已经被设置成了IoRecv,在判断时 就会将这次操作判断成接收操作,去检测接收BUFFER,这样显然就出错了;然后会接收到接收操作,此时IoType是IoRecv,仍然判断为接收操 作,此时检测接收BUFFER,是正确的。这样做的直观表现就是接收事件明显变多了。
以上的这个例子,说明处理IOCP时一定要细心,要注意那些变量是易变的,那些是不易变的。可能上面的这个看起来很明显,但是如果程序复杂了,这种BUG就不易察觉。
- IOCP的几点开发心得(补充)
- IOCP的几点开发心得
- IOCP的几点开发心得
- IOCP的几点细节
- iocp注意的几点
- IOCP的一些心得
- IOCP server设计需要注意的几点
- BlackBerry_JDE_PluginFull的几点使用心得
- String的几点知识心得
- app 开发的几点
- FCKEditor几点使用心得
- 几点“用户体验”心得
- JBuilder2006与JBoss4.2.2GA的几点使用心得
- VC Express 2008的几点使用心得
- FCKeditor的几点重要改进和使用心得
- Windows Server AppFabric缓存服务的几点实用心得
- 读马云专访的几点笔记与心得
- Windows Server AppFabric缓存服务的几点实用心得
- 如何利用js 控制 页面元素的隐藏显示
- android开发我的新浪微博客户端-用户授权页面UI篇(3.1)
- android开发我的新浪微博客户端-用户授权页面功能篇(3.2)
- 第五周任务(二)
- jQuery Ajax 全解析
- IOCP的几点开发心得
- ORA-01207 old control file完全解决方案
- android开发我的新浪微博客户端-登录页面UI篇(4.1)
- UNIX里面关于标准IO的几种缓冲机制
- mobile之 手机组成常识
- DML、DCL、DDL、DQL的介绍和区别(10级学员 姚荣旺课堂总结)
- map-reduce
- Dijkstra算法实现类—邻接矩阵,一般实现
- WCF实例模型