iocp_4_如何取得IO返回的操作结果,并作处理

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

<四>如何取得IO返回的操作结果,并作处理

在这一章中,我们的目标就集中在GetQueuedCompletionStatus。GetQueuedCompletionStatus 的作用就是从I/O出口队列中取得I/O操作结果。IOCP可以说是多入口(多种类型的函数可以提交I/O操作请求),单出口(一个函数就可以取得所有I/O操作的结果)。因此GetQueuedCompletionStatus 取得的结果将是复杂多样的。

BOOL(

HANDLE CompletionPort,

LPDWORD lpNumberOfBytes,

PULONG_PTR lpCompletionKey,

LPOVERLAPPED*lpOverlapped,

DWORD dwMilliseconds

);

在GetQueuedCompletionStatus中要重点关注以下几点:

(1)返回的布尔值// 操作成功与否的标志

(2)lpCompletionKey参数// 标志那个socket的I/O操作结果

(3)lpOverlapped参数// I/O操作得到的数据所在,看看I/O提交操作就知道了。

接下来,看看一份测试数据,会明白很多.

各种情况下,返回值和其它参数的值得情况,如下表:

说明:

1.ConnectEx 对方之后,如果成功连接,返回值为TRUE,lpNumberOfBytes为零,lpOverlapped不为0,lpCompletionKey 为绑定值

2.对方关闭之后,返回值为TRUE,lpNumberOfBytes 为零,lpOverlapped不为0。3.如果对方关闭后,socket没有关闭,而且还投递WSARecv请求,那么GetQueuedCompletionStatus会立刻返回,回到步骤2

4.ConnectEx 对方之后,如果对方拒绝连接,返回值为FALSE,lpOverlapped不为0,lpNumberOfBytes为零。

5.假如ConnectEx的对方不存在(超时),那么返回值为FALSE,lpOverlapped 不为0,lpCompletionKey 为绑定的值,lpNumberOfBytes为0,

6.任何情况下lpCompletionKey的值都是原先绑定的值

7.CompletionPort肯定不能为NULL,否则得到的值全部为空。

有了以上的表,是不是比MSDN上说的明白多了呢。下面看看代码如何实现:

void CIOCP_ClientDlg::IocpWorkerThread()

{

MYOVERLAPPED *lpOverlapped = NULL;

DWORD dwByteRecv = 0;

ULONG_PTR *PerHandleKey = NULL;

while (1)

{

lpOverlapped = NULL;

if(m_hIocp == NULL)

{

break;

}

//如果I/O 出口队列有结果,GetQueuedCompletionStatus则取得结果返回,否则等待 BOOL bResult = GetQueuedCompletionStatus(

m_hIocp, // 从这个IOCP中取得I/O操作结果

&dwByteRecv, // 发送或是接收了多少字节

(PULONG_PTR)&PerHandleKey,

(LPWSAOVERLAPPED*)&lpOverlapped,

INFINITE);

if (bResult == FALSE) // 对照表1.1,可能是连接超时、对方拒绝连接、断线

{

SOCKET socket = (SOCKET)PerHandleKey) ; // 转换,得到当初关联的socket

closesocket((SOCKET)PerHandleKey); // 出问题了,关闭socket

delete lpOverlapped ; // 释放OVERLAPPED

if (lpOverlapped == NULL) // 根据MSDN的说法,会出现这种情况

{

// 根据MSDN的说法,会出现这种情况,但测试时都没发生过

TRACE(TEXT("did not dequeue a pack from iocp queue.error:%d\n"), GetLastError());

continue;

}

else

{

// ERROR

TRACE(TEXT(" dequeued a pack from a failure iocp queue.error:%d\n"), GetLastError());

continue;

} // end if(lpOverlapped == NULL)

}

else

{

ASSERT(lpOverlapped != NULL); //

SOCKET socket = (SOCKET)PerHandleKey; // 取得关联的socket

switch (lpOverlapped->operateType) // 操作类型判别

{

case OP_CONNECT: // 连接操作,是成功的。

{

TRACE0("connected successfully!\n");

lpOverlapped->operateType = OP_RECV;//再次利用原有的OVERLAPPED

DWORD Flags = 0;

// 连接上之后,就要提交接收请求了,否则将收不到对方发过来的数据

if (WSARecv(socket, &lpOverlapped->wsabuf, 1,

&lpOverlapped->dwByteRecvSend, &Flags,

( LPWSAOVERLAPPED )lpOverlapped, NULL) == SOCKET_ERROR)

{

if (WSAGetLastError() == WSA_IO_PENDING)

{

TRACE0("Error == WSA_IO_PENDING\n");

}

else

{

TRACE0("Error occured at WSARecv()\n");

}

}

}

break;

case OP_ACCEPT:

{

// 得到一已连接的socket

SOCKET socketAccept = (SOCKET)lpOverlapped->pVoid;

//接下来就应该:

// (1)将socketAccept关联到IOCP ,代码略

相关文档
最新文档