WIN网络编程-IOCP服务程序-(3)

本文详细介绍了CIOCPServer中如何处理不同类型的IO操作,包括接受新连接、读写操作及错误处理等关键步骤,并阐述了上下文管理、缓冲区分配与释放等重要机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

void CIOCPServer::HandleIO(DWORD dwKey, CIOCPBuffer *pBuffer, DWORD dwTrans, int nError)
{
 CIOCPContext *pContext = (CIOCPContext *)dwKey;

#ifdef _DEBUG
   ::OutputDebugString(" HandleIO... /n");
#endif // _DEBUG
 
 // 1)首先减少套节字上的未决I/O计数
 if(pContext != NULL)
 {
  ::EnterCriticalSection(&pContext->Lock);
 
  if(pBuffer->nOperation == OP_READ)
   pContext->nOutstandingRecv --;
  else if(pBuffer->nOperation == OP_WRITE)
   pContext->nOutstandingSend --;
 
  ::LeaveCriticalSection(&pContext->Lock);
 
  // 2)检查套节字是否已经被我们关闭
  if(pContext->bClosing)
  {
#ifdef _DEBUG
   ::OutputDebugString(" 检查到套节字已经被我们关闭 /n");
#endif // _DEBUG
   if(pContext->nOutstandingRecv == 0 && pContext->nOutstandingSend == 0)
   { 
    ReleaseContext(pContext);
   }
   // 释放已关闭套节字的未决I/O
   ReleaseBuffer(pBuffer);
   return;
  }
 }
 else
 {
  RemovePendingAccept(pBuffer);
 }

 // 3)检查套节字上发生的错误,如果有的话,通知用户,然后关闭套节字
 if(nError != NO_ERROR)
 {
  if(pBuffer->nOperation != OP_ACCEPT)
  {
   OnConnectionError(pContext, pBuffer, nError);
   CloseAConnection(pContext);
   if(pContext->nOutstandingRecv == 0 && pContext->nOutstandingSend == 0)
   { 
    ReleaseContext(pContext);
   }
#ifdef _DEBUG
   ::OutputDebugString(" 检查到客户套节字上发生错误 /n");
#endif // _DEBUG
  }
  else // 在监听套节字上发生错误,也就是监听套节字处理的客户出错了
  {
   // 客户端出错,释放I/O缓冲区
   if(pBuffer->sClient != INVALID_SOCKET)
   {
    ::closesocket(pBuffer->sClient);
    pBuffer->sClient = INVALID_SOCKET;
   }
#ifdef _DEBUG
   ::OutputDebugString(" 检查到监听套节字上发生错误 /n");
#endif // _DEBUG
  }

  ReleaseBuffer(pBuffer);
  return;
 }


 // 开始处理
 if(pBuffer->nOperation == OP_ACCEPT)
 {
  if(dwTrans == 0)
  {
#ifdef _DEBUG
   ::OutputDebugString(" 监听套节字上客户端关闭 /n");
#endif // _DEBUG
  
   if(pBuffer->sClient != INVALID_SOCKET)
   {
    ::closesocket(pBuffer->sClient);
    pBuffer->sClient = INVALID_SOCKET;
   }
  }
  else
  {
   // 为新接受的连接申请客户上下文对象
   CIOCPContext *pClient = AllocateContext(pBuffer->sClient);
   if(pClient != NULL)
   {
    if(AddAConnection(pClient))
    {
     // 取得客户地址
     int nLocalLen, nRmoteLen;
     LPSOCKADDR pLocalAddr, pRemoteAddr;
     m_lpfnGetAcceptExSockaddrs(
      pBuffer->buff,
      pBuffer->nLen - ((sizeof(sockaddr_in) + 16) * 2),
      sizeof(sockaddr_in) + 16,
      sizeof(sockaddr_in) + 16,
      (SOCKADDR **)&pLocalAddr,
      &nLocalLen,
      (SOCKADDR **)&pRemoteAddr,
      &nRmoteLen);
     memcpy(&pClient->addrLocal, pLocalAddr, nLocalLen);
     memcpy(&pClient->addrRemote, pRemoteAddr, nRmoteLen);
    
     // 关联新连接到完成端口对象
     ::CreateIoCompletionPort((HANDLE)pClient->s, m_hCompletion, (DWORD)pClient, 0);
    
     // 通知用户
     pBuffer->nLen = dwTrans;
     OnConnectionEstablished(pClient, pBuffer);
    
     // 向新连接投递几个Read请求,这些空间在套节字关闭或出错时释放
     for(int i=0; i<5; i++)
     {
      CIOCPBuffer *p = AllocateBuffer(BUFFER_SIZE);
      if(p != NULL)
      {
       if(!PostRecv(pClient, p))
       {
        CloseAConnection(pClient);
        break;
       }
      }
     }
    }
    else // 连接数量已满,关闭连接
    {
     CloseAConnection(pClient);
     ReleaseContext(pClient);
    }
   }
   else
   {
    // 资源不足,关闭与客户的连接即可
    ::closesocket(pBuffer->sClient);
    pBuffer->sClient = INVALID_SOCKET;
   }
  }
 
  // Accept请求完成,释放I/O缓冲区
  ReleaseBuffer(pBuffer);

  // 通知监听线程继续再投递一个Accept请求
  ::InterlockedIncrement(&m_nRepostCount);
  ::SetEvent(m_hRepostEvent);
 }
 else if(pBuffer->nOperation == OP_READ)
 {
  if(dwTrans == 0) // 对方关闭套节字
  {
   // 先通知用户
   pBuffer->nLen = 0;
   OnConnectionClosing(pContext, pBuffer);
   // 再关闭连接
   CloseAConnection(pContext);
   // 释放客户上下文和缓冲区对象
   if(pContext->nOutstandingRecv == 0 && pContext->nOutstandingSend == 0)
   { 
    ReleaseContext(pContext);
   }
   ReleaseBuffer(pBuffer);
  }
  else
  {
   pBuffer->nLen = dwTrans;
   // 按照I/O投递的顺序读取接收到的数据
   CIOCPBuffer *p = GetNextReadBuffer(pContext, pBuffer);
   while(p != NULL)
   {
    // 通知用户
    OnReadCompleted(pContext, p);
    // 增加要读的序列号的值
    ::InterlockedIncrement((LONG*)&pContext->nCurrentReadSequence);
    // 释放这个已完成的I/O
    ReleaseBuffer(p);
    p = GetNextReadBuffer(pContext, NULL);
   }

   // 继续投递一个新的接收请求
   pBuffer = AllocateBuffer(BUFFER_SIZE);
   if(pBuffer == NULL || !PostRecv(pContext, pBuffer))
   {
    CloseAConnection(pContext);
   }
  }
 }
 else if(pBuffer->nOperation == OP_WRITE)
 {

  if(dwTrans == 0) // 对方关闭套节字
  {
   // 先通知用户
   pBuffer->nLen = 0;
   OnConnectionClosing(pContext, pBuffer);

   // 再关闭连接
   CloseAConnection(pContext);

   // 释放客户上下文和缓冲区对象
   if(pContext->nOutstandingRecv == 0 && pContext->nOutstandingSend == 0)
   { 
    ReleaseContext(pContext);
   }
   ReleaseBuffer(pBuffer);
  }
  else
  {
   // 写操作完成,通知用户
   pBuffer->nLen = dwTrans;
   OnWriteCompleted(pContext, pBuffer);
   // 释放SendText函数申请的缓冲区
   ReleaseBuffer(pBuffer);
  }
 }
}


BOOL CIOCPServer::SendText(CIOCPContext *pContext, char *pszText, int nLen)
{
 CIOCPBuffer *pBuffer = AllocateBuffer(nLen);
 if(pBuffer != NULL)
 {
  memcpy(pBuffer->buff, pszText, nLen);
  return PostSend(pContext, pBuffer);
 }
 return FALSE;
}


void CIOCPServer::OnConnectionEstablished(CIOCPContext *pContext, CIOCPBuffer *pBuffer)
{
}

void CIOCPServer::OnConnectionClosing(CIOCPContext *pContext, CIOCPBuffer *pBuffer)
{
}


void CIOCPServer::OnReadCompleted(CIOCPContext *pContext, CIOCPBuffer *pBuffer)
{
}

void CIOCPServer::OnWriteCompleted(CIOCPContext *pContext, CIOCPBuffer *pBuffer)
{
}

void CIOCPServer::OnConnectionError(CIOCPContext *pContext, CIOCPBuffer *pBuffer, int nError)
{
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值