完成端口笔记

1. GetQueuedCompletionStatus 返回值问题

参考:http://wenku.baidu.com/view/7e205c2ced630b1c59eeb5c8.html

Return value

CompletionPort

lpNumberOfBytes

lpCompletionKey

lpOverlapped

WSAGetLastError()

连接成功

1 == TRUE

1 == NOT NULL

0(值为0 )

1 == NOT NULL

1(NOT NULL)

0

连接超时

0

1

0

1

1

121

对方拒绝

0

1

0

1

1

1225

对方关闭

1

1

0

1

1

0

断线

0

1

0

1

1

数据

1

1

1 == NOT NULL

1

1

0

未知情况

1

1

0

1

0

本地关闭

0

1

0

1

1

64

说明:

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,否则得到的值全部为空。

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 ,代码略
                    //  (2)提交接收请求,代码略
                }
                break;
            case OP_SEND:
                {
                    //ASSERT(dwByteRecv == lpOverlapped->wsabuf.len);
                    if(dwByteRecv != lpOverlapped->wsabuf.len)
                    {
                        ASSERT(FALSE);  // 没实际用途,只做测试
                        // ....
                    }
                    //    TRACE0("send completely!\n");
                    delete lpOverlapped;   // 发送操作成功了,释放OVERLAPPED 结构

                    
                }
                break;
            case OP_RECV:
                {
                    TRACE0("recv completely!\n");
                    if(0 == dwByteRecv )   // 由表1.1知道对方已经关闭
                    {
                        TRACE0("Peer have been closed , me clsoe too.");
                        closesocket(socket); // 关闭socket
                        delete lpOverlapped ;
                        continue;
                    }

                    // 处理数据,数据在lpOverlapped->wsabuf->buf中
                    //// 接下来,继续提交接受请求,且再次利用原来的OVERLAPPED结构
                    lpOverlapped->operateType = OP_RECV;
                    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");
                        }
                    } // end if(WSARecv…
                } // case OP_RECV
                break;
            default:
                {
                    TRACE(TEXT("default...error happen\n"));
                }
            }
        }  // end if (bResult == 0)
    }  // end while(1)
    TRACE(_T("exit iocp work thread \n"));
}
View Code
原文地址:https://www.cnblogs.com/mutou3221/p/3116033.html