在用 BOOL GetQueuedCompletionStatus(
  HANDLE CompletionPort,
  LPDWORD lpNumberOfBytes,
  PULONG_PTR lpCompletionKey,
  LPOVERLAPPED* lpOverlapped,
  DWORD dwMilliseconds
);
函数等待接收数据返回时,我看到有些程序例子是在lpCompletionKey参数中取得客户发送来的数据,
有些例子又是在lpOverlapped参数中取得数据,这是为什么,又如何设定在哪个参数中取得数据

解决方案 »

  1.   

    DWORD __stdcall   CompletionRoutine(LPVOID Param)
    {
    CompletionPortModel* pCP = (CompletionPortModel*)Param;
    DWORD dwNumberBytes;
    PPER_HANDLE_CONTEXT lpHandleContext = NULL;
    LPWSAOVERLAPPED lpOverlapped = NULL;
    int nResult;
    BOOL bSuccess;
    EnterCriticalSection(&pCP->m_CPCriSection);
    ++ pCP->CPThreadCount;
    LeaveCriticalSection(&pCP->m_CPCriSection);
    TRACE("第%d个完成端口处理线程启动。\n",pCP->CPThreadCount); while (pCP->CPThreadRun == 1)
    {
    bSuccess = GetQueuedCompletionStatus(pCP->m_hCOP,&dwNumberBytes,(PULONG_PTR )&lpHandleContext,&lpOverlapped,1000);//INFINITE); PPER_IO_CONTEXT lpPerIoContext = (PPER_IO_CONTEXT)lpOverlapped;
    if (FALSE == bSuccess && pCP->CPThreadRun == 1)
    {#ifndef _DEBUG
    TRACE( "GetQueuedCompletionStatus() failed: %d" , GetLastError());
    #endif
    if (lpPerIoContext)
    {
    pCP->ReleaseClient(lpPerIoContext); pCP->InsertToLookaside(lpPerIoContext, NULL);
    }
    if (lpHandleContext)
    {
    lpHandleContext->pNext = NULL;
    pCP->InsertToLookaside(NULL, lpHandleContext);
    } continue;
    }
    if (pCP->CPThreadRun == 1)
    {
    if (NULL == lpHandleContext)
    {
    //
    //PostQueuedCompletionStatus发过来一个空的单句柄数据,表示线程要退出了。
    //
    TRACE("第%d个完成端口处理线程退出:PostQueuedCompletionStatus发过来一个空的单句柄数据,表示线程要退出了\n",pCP->CPThreadCount);
    --pCP->CPThreadCount;
    return 0;
    }
    #ifdef _DEBUG
    // TRACE( "recv buffer data: %s %d\n", lpPerIoContext->szBuffer,lpPerIoContext->dataLen);
    #endif

    if(IoAccept != lpPerIoContext->IoOperation && 0 == dwNumberBytes)//非连接消息且收发数据长度为0,则关闭连接
    {
    pCP->OnClientClose(lpPerIoContext->unId);
    pCP->ReleaseClient(lpPerIoContext);
    pCP->InsertToLookaside(lpPerIoContext, NULL); lpHandleContext->pNext = NULL;
    pCP->InsertToLookaside(NULL, lpHandleContext);

    continue;
    } HANDLE hResult;
    PPER_HANDLE_CONTEXT lpNewperHandleContext = NULL; switch(lpPerIoContext->IoOperation)
    {
    case IoAccept : 
    if (dwNumberBytes > 0)
    {
    //
    //第一次连接成功并且收到了数据,将这个结点从链表中解除
    //
    EnterCriticalSection(&pCP->m_ListCriSection);
    pCP->ReleaseNode(lpPerIoContext);
    LeaveCriticalSection(&pCP->m_ListCriSection);
    }
    //将客户连接和服务器监听连接关联,即在客户连接中设置服务器监听连接
    nResult = setsockopt(lpPerIoContext->sClient, 
    SOL_SOCKET,
    SO_UPDATE_ACCEPT_CONTEXT,
    (char *)&pCP->m_ListenSocket,
    sizeof(pCP->m_ListenSocket)
    );
    if(SOCKET_ERROR == nResult) 
    {
    TRACE( "SO_UPDATE_ACCEPT_CONTEXT failed to update accept socket\n" );
    pCP->ReleaseClient(lpPerIoContext);
    pCP->InsertToLookaside(lpPerIoContext, NULL);

    continue;
    }

    //获取一个空闲的节点
    lpNewperHandleContext = pCP->GetHandleFromLookaside();//获取一个空闲节点
    if (NULL == lpNewperHandleContext)//无且创建失败
    {
    TRACE( "HeapAlloc() for lpNewperHandlecontext failed\n" );
    pCP->ReleaseClient(lpPerIoContext);
    pCP->InsertToLookaside(lpPerIoContext, NULL);

    continue;
    } lpNewperHandleContext->pNext = NULL;

    //
    //将新建立的套接字关联到完成端口
    //
    hResult = CreateIoCompletionPort(
    (HANDLE)lpPerIoContext->sClient,\
    pCP->m_hCOP,
    (DWORD_PTR)lpNewperHandleContext,
    0
    );
    if (NULL == hResult)
    {
    TRACE( "将新建立的套接字关联到完成端口时,CreateIoCompletionPort() failed:%d ", GetLastError()); pCP->ReleaseClient(lpPerIoContext);
    pCP->InsertToLookaside(lpPerIoContext, NULL);
    lpNewperHandleContext->pNext = NULL;
    pCP->InsertToLookaside(NULL, lpNewperHandleContext);

    continue;
    }
    //保留完成键
    pCP->AddClient(lpPerIoContext); int flags;
    if (dwNumberBytes > 0)//同时收到数据
    {
    lpPerIoContext->dataLen = dwNumberBytes;
    flags = IO_READ_COMPLETION;
    }
    else//如果连接成功但是没有收到数据
    {
    lpPerIoContext->dataLen = 0;
    flags = IO_ACCEPT_COMPLETION;
    }
    pCP->IOActionFinish(lpPerIoContext,flags );
    bSuccess = pCP->IOAction(lpPerIoContext);
    if (FALSE == bSuccess)
    {
    continue;
    }
    break;//end of case IoAccept

    case IoRead:
    pCP->IOActionFinish(lpPerIoContext, IO_READ_COMPLETION);
    bSuccess = pCP->IOAction(lpPerIoContext);
    if (FALSE == bSuccess)
    {
    continue;
    } break;//end of case IoRead case IoWrite:
    pCP->IOActionFinish(lpPerIoContext, IO_WRITE_COMPLETION);
    bSuccess = pCP->IOAction(lpPerIoContext);
    if (FALSE == bSuccess)
    {
    continue;
    } break; default:
    continue;
    break;
    }
    }
    } TRACE("第%d个完成端口处理线程退出。\n",pCP->CPThreadCount);
    EnterCriticalSection(&pCP->m_CPCriSection);
    --pCP->CPThreadCount;
    LeaveCriticalSection(&pCP->m_CPCriSection);
    return 0;}//end of CompletionRoutine()
      

  2.   

    //
    //发送接收数据后处理
    //
    BOOL  JhCpServer::IOActionFinish(PPER_IO_CONTEXT lpPerIoContext,int nFlags)
    {
    //
    //nFlags == IO_READ_COMPLETION表示完成的上一次IO操作是WSARecv。
    //
    if (IO_READ_COMPLETION == nFlags)
    {
    //
    //完成了WSARecv,添加数据到缓冲区
    //
    if (lpPerIoContext->dataLen > 0)
    {
    AddRecvData(lpPerIoContext->sClient,lpPerIoContext->wsaBuffer.buf,lpPerIoContext->dataLen);
    }
    //lpPerIoContext->ContinueAction = ContinueWrite;
    //if (server)
    //{
    // SOCKETDATA sd;
    // sd.s = lpPerIoContext->sClient;
    // sd.pData = lpPerIoContext->wsaBuffer.buf;
    // sd.DataLen = lpPerIoContext->dataLen;
    // server->OnReceive(&sd);
    //}
    // //
    //转向发送
    //
    TrySend(lpPerIoContext);

    return TRUE;
    } if (IO_WRITE_COMPLETION == nFlags)
    {
    //
    //上一次IO操作WSASend数据发送完成,可以将后续操作标志设置为关闭则关闭连接
    //如果不需要关闭而是要继续发送,将lpPerIoContext->IoOperation设置为
    //IoWrite,如果要继续接收,将lpPerIoContext->IoOperation设置为
    //IoRead,并初始化好BUFFER。
    //
    if (server && lpPerIoContext->dataLen > 0)//发送成功 
    {
    server->OnSendSuccess(lpPerIoContext->sClient,lpPerIoContext->dataLen);
    }

    TrySend(lpPerIoContext); return TRUE;
    }
    if (IO_ACCEPT_COMPLETION == nFlags)
    {
    //
    //刚建立了一个连接,并且没有收发数据,,,,
    //
    lpPerIoContext->IoOperation = IoRead;
    // ZeroMemory(&(lpPerIoContext->ol), sizeof(WSAOVERLAPPED));
    // ZeroMemory(lpPerIoContext->szBuffer, BUFFER_SIZE);
    // lpPerIoContext->wsaBuffer.len = BUFFER_SIZE;
    // lpPerIoContext->wsaBuffer.buf = lpPerIoContext->szBuffer; if (server)
    {
    server->OnConnect(lpPerIoContext->sClient);
    }
    return TRUE;
    }

    return FALSE;
    }//
    //试图发送
    //
    void JhCpServer::TrySend(PPER_IO_CONTEXT lpPerIoContext)
    {
    //取得最近一个 发送数据包
    ZeroMemory(&(lpPerIoContext->ol), sizeof(WSAOVERLAPPED));
    ZeroMemory(lpPerIoContext->szBuffer, BUFFER_SIZE);
    if (lpPerIoContext->sendBuf == NULL)//转向继续接收
    {
    lpPerIoContext->IoOperation = IoRead;
    }
    else//转向发送
    {
    EnterCriticalSection(&lpPerIoContext->sendCriticalSection);
    if (lpPerIoContext->sendBuf->SendOffset + lpPerIoContext->dataLen >= lpPerIoContext->sendBuf->GetDataLen())//该数据包是否已经发送完
    {
    SendData* nextData = lpPerIoContext->sendBuf;
    lpPerIoContext->sendBuf = (SendData*)nextData->next;
    Del(nextData);
    }
    else
    {
    lpPerIoContext->sendBuf->SendOffset += lpPerIoContext->dataLen;
    }
    if (lpPerIoContext->sendBuf != NULL)
    {
    lpPerIoContext->dataLen = min(BUFFER_SIZE,lpPerIoContext->sendBuf->GetDataLen() - lpPerIoContext->sendBuf->SendOffset);
    memcpy(lpPerIoContext->szBuffer,lpPerIoContext->sendBuf->GetData() + lpPerIoContext->sendBuf->SendOffset,lpPerIoContext->dataLen);
    lpPerIoContext->wsaBuffer.len = lpPerIoContext->dataLen;
    lpPerIoContext->IoOperation = IoWrite;
    }
    else//没有了,转向接收
    {
    lpPerIoContext->IoOperation = IoRead;
    lpPerIoContext->dataLen = 0;
    lpPerIoContext->wsaBuffer.len = BUFFER_SIZE;
    }
    LeaveCriticalSection(&lpPerIoContext->sendCriticalSection);
    }
    }//
    //执行发送或者接收数据
    //
    BOOL  JhCpServer::IOAction( PPER_IO_CONTEXT lpPerIoContext)
    {
    int nResult;
    DWORD dwFlags = 0,dwSend = 0;
    //
    //发送数据且发送数据长度大于0
    //
    if (IoWrite == lpPerIoContext->IoOperation && lpPerIoContext->dataLen > 0)
    {
    nResult = WSASend(lpPerIoContext->sClient,
    &(lpPerIoContext->wsaBuffer),
    1,
    &dwSend,
    0,
    &(lpPerIoContext->ol),
    NULL
    );
    if((SOCKET_ERROR == nResult) && (ERROR_IO_PENDING != WSAGetLastError()))
    {
    TRACE( "WSASend() failed:%d " ,WSAGetLastError() );
    if (server) server->OnSendFail(lpPerIoContext->sClient,WSAGetLastError());

    ReleaseClient(lpPerIoContext);

    return FALSE;
    }
    else
    {
    TRACE("Send data %d %d bytes success.\n ",lpPerIoContext->dataLen,dwSend);
    }
    }

    //
    //读取数据
    //
    if (IoRead == lpPerIoContext->IoOperation)
    {
    lpPerIoContext->dataLen = 0;
    lpPerIoContext->wsaBuffer.len = BUFFER_SIZE;
    nResult = WSARecv(lpPerIoContext->sClient,
    &(lpPerIoContext->wsaBuffer),
    1,
    &lpPerIoContext->dataLen,
    &dwFlags,
    &(lpPerIoContext->ol),
    NULL
    );

    if((SOCKET_ERROR==nResult) && (ERROR_IO_PENDING != WSAGetLastError()))
    {
    TRACE( "WSARecv() failed:%d " , WSAGetLastError() );
    if (server) server->OnReceiveFail( lpPerIoContext->sClient,WSAGetLastError()); ReleaseClient(lpPerIoContext);

    return FALSE;
    }
    else
    {
    TRACE("Receive data %d bytes.\n",lpPerIoContext->dataLen);
    }

    }

    //
    //关闭客户连接
    //
    if (IoEnd == lpPerIoContext->IoOperation)
    {
    ReleaseClient(lpPerIoContext);//释放资源
    InsertToLookaside(lpPerIoContext,NULL);//插入到空闲链表中备用
    } return TRUE;
    }
      

  3.   

    前一个取得XX,后一个取得YY。
      

  4.   

    楼上正解,接受到的数据只与你给WSARecv()投递的接受缓冲区在哪个自定义的结构体中,
    GetQueCompletionPort()只是判断完成端口的状态
      

  5.   

    lpCompletionKey参数:是你在createcompletionport函数建立关联时传递的,记录连接上来的socket数据自定义结构;
    lpOverlapped参数:是你在进行数据收发时传递的,记录每次IO数据自定义结构。