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

原创 2006年06月01日 02:49:00
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()  
 

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

Socket通讯 完成端口 怎么实现同时收发

Socket通讯 完成端口 同时收发 接收 发送

完成端口详细说明(接受连接请求)

 服务器要做的最普通的事情之一就是接受来自客户端的连接请求。在套接字上使用重叠I/O接受连接的惟一API就是AcceptEx()函数。有趣的是,通常的同步接受函数accept()的返回值是一个新的套接...

完成端口的回射服务器,给别人的代码添加了补丁(竞争问题,发送数据)

cpp文件 #include "StdAfx.h" #include "IOCPModel.h" #include "MainDlg.h" // 每一个处理器上产生多少个线程(为了最大限度的提升服...

hadoop使用pig进行数据分析时遇到的问题(10020号端口问题,连接拒绝)

编写hadoop应用程序的map与reduce并不难,但是要完整控制整个框架的编写,需要对Java语言非常非常熟悉。而我一直做Linux下C编程的人,只能寻找更加适合我的方式。Apache项目下给出了...

关于单片机TCP/IP协议栈的实现目前的进度和问题——TCP或UDP发送数据,端口绑定问题

这段时间研究TCP/IP协议,用于单片机通信。昨天为止,基本实现了基础通信(ARP,UDP,ICMP_Ping,TCP)。 1,ARP主动,被动可以实现,但是要知道一般基于路由器下的主机,无论ARP...

用C++实现HTTP服务器 - 处理完成端口模型(IOCP)的超时问题

如何处理完成端口模型(IOCP)的超时问题. 作者: 阙荣文  2011/7/12 前言 完成端口(IOCP)是所有Windows I/O模型中最复杂,也是性能最好的一种.在关于IOCP...
  • querw
  • querw
  • 2011年07月12日 15:55
  • 15428

iocp(完成端口)采用WSARecv WSASend处理数据,WSASend群发(广播)消息

最近在耍iocp,也在网上看了不少例子,但却基本没看到使用WSASend群发的例子 最多只是使用WSASend将数据回传,而这个功能相对比较简单,只要学会使用WSARecv 回传则比较容易实现,而...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:于完成端口的数据接收问题
举报原因:
原因补充:

(最多只允许输入30个字)