• 完成端口笔记


    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
  • 相关阅读:
    eclipse下切换svn用户
    Netty实现服务端客户端长连接通讯及心跳检测
    Spring Batch系列总括(转载)
    SQL中的Null深入研究分析
    MySQL报错“1366
    Memcache学习php完整一例
    Memcache学习笔记
    递归和迭代区别
    解决textarea 输出有空格问题
    解决mysql安装出现error Nr.1045问题
  • 原文地址:https://www.cnblogs.com/mutou3221/p/3116033.html
Copyright © 2020-2023  润新知