关闭

于完成端口的数据接收问题

3555人阅读 评论(0) 收藏 举报
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楼  JasonHeung   (拥有一切不过就这样笑着哭) 三级用户 该版得分小于等于1000分,大于500分  回复于 2005-02-05 14:28:51  得分 5

//  
  //发送接收数据后处理  
  //  
  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;  
  }  
 
Top
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:190857次
    • 积分:2626
    • 等级:
    • 排名:第13854名
    • 原创:66篇
    • 转载:9篇
    • 译文:0篇
    • 评论:19条
    最新评论