iocp.cpp

iocp.cpp 2011-3-3 21:31阅读(1)
  1. // IOCPServer.cpp: implementation of the CIOCPServer class.    
  2. //    
  3. //    
  4. #include "stdafx.h"    
  5. #include "IOCPServer.h"    
  6. //    
  7. // Construction/Destruction    
  8. //    
  9. CIOCPServer::CIOCPServer()   
  10. {   
  11.     //socket初始化    
  12.     WSADATA wsd;   
  13.     WORD wVersionRequested = MAKEWORD(2, 2);   
  14.     int nResult = WSAStartup(wVersionRequested, &wsd);   
  15.     if (nResult == SOCKET_ERROR)   
  16.     {   
  17.         WSACleanup();   
  18.         PRINTDEBUG(WSAGetLastError());   
  19.     }   
  20.        
  21.     if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2)   
  22.     {   
  23.         WSACleanup();   
  24.     }   
  25.        
  26.     m_hKillEvent = CreateEvent(NULL, TRUE, FALSE, NULL);   
  27.     printf("socket init successful... \n");   
  28. }   
  29.    
  30. CIOCPServer::~CIOCPServer()   
  31. {   
  32.     WSACleanup();   
  33. }   
  34.    
  35. //分配连接overlappedplus    
  36. LPOVERLAPPEDPLUS  CIOCPServer::AllocateOverlappedPlus(IOType ioType)   
  37. {   
  38.     OVERLAPPEDPLUS* pOlp = NULL;   
  39.        
  40.     pOlp = new OVERLAPPEDPLUS;   
  41.     ZeroMemory(pOlp, sizeof(OVERLAPPEDPLUS));   
  42.     pOlp->opCode = ioType;   
  43.        
  44.     return pOlp;       
  45. }   
  46.    
  47. //分配连接进入的客户的相关信息    
  48. LPCLIENTCONTEXT  CIOCPServer::AllocateContext()   
  49. {   
  50.     LPCLIENTCONTEXT lpContext = NULL;   
  51.        
  52.     lpContext = new CLIENTCONTEXT;   
  53.     ZeroMemory(lpContext, sizeof(CLIENTCONTEXT));   
  54.     lpContext->m_wsaInBuffer.buf = lpContext->m_byInBuffer;   
  55.     lpContext->m_wsaInBuffer.len = BUFSIZE;   
  56.    
  57.     lpContext->m_hWriteComplete = CreateEvent(NULL, FALSE, TRUE, NULL);   
  58.    
  59.     return lpContext;      
  60. }   
  61.    
  62. //释放overlappedplus    
  63. void  CIOCPServer::FreeOverlappedPlus(LPOVERLAPPEDPLUS lpOlp)   
  64. {   
  65.     delete lpOlp;      
  66. }   
  67.    
  68. //根据消息overlapped的类型,处理消息,返回值TRUE:继续读,FALSE,不读    
  69. //一般写事件就不让他都返回FALSE,没有必要再读了!    
  70. BOOL CIOCPServer::ProcessIOMessage(IOType opCode, LPCLIENTCONTEXT lpContext , DWORD dwIoSize)   
  71. {   
  72.     BOOL bRet = FALSE;     
  73.     //根据opCode确定操作    
  74.     switch (opCode)   
  75.     {   
  76.     case OP_IOInitialize:   
  77.         bRet = OnClientInitializing(lpContext, dwIoSize);   
  78.         break;   
  79.     case OP_IORead:   
  80.         bRet = OnClientReading(lpContext, dwIoSize);   
  81.         break;   
  82.     case OP_IOWrite:   
  83.         bRet = OnClientWriting(lpContext, dwIoSize);   
  84.         break;   
  85.     default:   
  86.         printf("worker thread:unknown operation...\n");   
  87.     }   
  88.     return bRet;    
  89. }   
  90.    
  91. //关闭完成端口    
  92. void CIOCPServer::CloseCompletionPort( )   
  93. {   
  94.     PostQueuedCompletionStatus(m_hIocp, 0, (DWORD) NULL, NULL);    
  95.     // Close the CompletionPort and stop any more requests    
  96.     CloseHandle(m_hIocp);      
  97. }   
  98.    
  99. void CIOCPServer::CreateWorkerThread()   
  100. {   
  101.     SYSTEM_INFO sysinfo;   
  102.     DWORD dwThreadId;   
  103.        
  104.     //在completion port上等待的线程数为:CPU*2+2    
  105.     GetSystemInfo(&sysinfo);   
  106.     m_dwThreads  = sysinfo.dwNumberOfProcessors*2+2;   
  107.        
  108.     printf("create worker thread num: %d \n", m_dwThreads);   
  109.     for(UINT i=0;i<M_DWTHREADS;I++) bResult="GetQueuedCompletionStatus(pIocpServer-" BOOL bEnterRead="TRUE;" bError="FALSE;" { (TRUE) while lpOlp; LPOVERLAPPEDPLUS lpOverlapped; LPWSAOVERLAPPED lpContext; LPCLIENTCONTEXT dwNumRead; DWORD *)lpParam; *pIocpServer="(CIOCPServer" CIOCPServer lpParam) * void CIOCPServer::CompletionWorkerThread( WINAPI 绑定在端口上工作线程 } CloseHandle(hThread); &dwThreadId); 0, (LPVOID)this, CompletionWorkerThread, hThread="CreateThread(NULL," hThread; HANDLE>m_hIocp,    
  110.             &dwNumRead,   
  111.             (LPDWORD)&lpContext,   
  112.             &lpOverlapped,   
  113.             INFINITE);   
  114.            
  115.         //获得LPOVERLAPPEDPLUS指针    
  116.         lpOlp = CONTAINING_RECORD(lpOverlapped, OVERLAPPEDPLUS, ol);   
  117.         printf("Event comming %d\n", lpOlp->opCode);   
  118.            
  119.         //非timeout引起的错误, 相关信息没有从GetQueuedCompletionStatus中返回    
  120.         if (!bResult && lpOlp == NULL && WAIT_TIMEOUT != WSAGetLastError())   
  121.         {   
  122.             PRINTDEBUG(WSAGetLastError());   
  123.             // 发生错误    
  124.             bError = TRUE;   
  125.         }   
  126.         //错误,但是相关信息从GetQueuedCompletionStatus中返回    
  127.         //可能原因之一是:客户强制退出了!    
  128.         else if(!bResult && lpOlp != NULL)   
  129.         {   
  130.             PRINTDEBUG(WSAGetLastError());   
  131.             pIocpServer->FreeClientContext(lpContext);   
  132.             //循环继续,不应该读了!    
  133.             continue;   
  134.         }   
  135.    
  136.         //无错误,处理事件    
  137.         if (!bError)    
  138.         {   
  139.             if(bResult && NULL != lpOlp && NULL != lpContext)    
  140.             {   
  141.                 bEnterRead = pIocpServer->ProcessIOMessage(lpOlp->opCode, lpContext, dwNumRead);   
  142.             }   
  143.         }   
  144.            
  145.         //无错 && 读    
  146.         if(! bError && bEnterRead)    
  147.         {   
  148.             LPOVERLAPPEDPLUS lpOlp = pIocpServer->AllocateOverlappedPlus(OP_IORead);   
  149.             ULONG           ulFlags = MSG_PARTIAL;   
  150.                
  151.             ZeroMemory(lpContext->m_wsaInBuffer.buf, lpContext->m_wsaInBuffer.len);   
  152.             UINT nRetVal = WSARecv(lpContext->m_Socket,    
  153.                 &lpContext->m_wsaInBuffer,   
  154.                 1,   
  155.                 &dwNumRead,    
  156.                 &ulFlags,   
  157.                 &lpOlp->ol,    
  158.                 NULL);   
  159.    
  160.             if ( nRetVal == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)    
  161.             {   
  162.                 printf("CLIENT abortive exit\n");   
  163.                 pIocpServer->FreeClientContext(lpContext);   
  164.             }   
  165.    
  166.         }          
  167.            
  168.         pIocpServer->FreeOverlappedPlus(lpOlp);   
  169.            
  170.     }   
  171.     return 0;   
  172. }   
  173.    
  174. BOOL CIOCPServer::Initialize(DWORD conns, int port)   
  175. {   
  176.     m_sListen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);   
  177.     if(m_sListen == SOCKET_ERROR)   
  178.     {   
  179.         PRINTDEBUG(WSAGetLastError());   
  180.         return FALSE;   
  181.     }   
  182.        
  183.     printf("create listening socket successful... \n");   
  184.        
  185.     //需要绑定的本地地址    
  186.     sockaddr_in local;   
  187.     memset(&local, 0, sizeof(local));   
  188.     local.sin_addr.s_addr = htonl(INADDR_ANY);     
  189.     local.sin_family = AF_INET;   
  190.     local.sin_port = htons(port);   
  191.        
  192.     //绑定,将监听端口绑定到本地地址    
  193.     if(bind(m_sListen, (sockaddr*)&local,sizeof(local))   
  194.         == SOCKET_ERROR)   
  195.     {   
  196.         PRINTDEBUG(WSAGetLastError());   
  197.         return FALSE;   
  198.     }   
  199.        
  200.     printf("bind local socket successful... \n");   
  201.        
  202.     //产生完成端口    
  203.     m_hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);   
  204.     if(m_hIocp == NULL)   
  205.     {   
  206.         PRINTDEBUG(WSAGetLastError());   
  207.         return FALSE;   
  208.     }   
  209.        
  210.     printf("create completion port successful... \n");   
  211.    
  212.     CreateWorkerThread();   
  213.     printf("listening socket... \n");   
  214.     //监听线程    
  215.     listen(m_sListen, conns);   
  216.    
  217.     return TRUE;   
  218. }   
  219.    
  220. void CIOCPServer::Accept()   
  221. {   
  222.     sockaddr_in client;   
  223.     int sClientLength = sizeof(client);   
  224.     while (WAIT_TIMEOUT == WaitForSingleObject(m_hKillEvent, 0))   
  225.     {   
  226.         printf("waiting for client connecting... \n");   
  227.            
  228.         //等待客户连接    
  229.         SOCKET clientSocket = accept(m_sListen, (sockaddr*)&client, &sClientLength);   
  230.         if(clientSocket == SOCKET_ERROR)   
  231.         {   
  232.             PRINTDEBUG(WSAGetLastError());     
  233.             continue;   
  234.         }   
  235.            
  236.         printf("a new client comming... \n");   
  237.            
  238.         //设置completion key    
  239.         LPCLIENTCONTEXT lpContext = AllocateContext();   
  240.         lpContext->m_Socket = clientSocket;         
  241.         sprintf(lpContext->m_ip,inet_ntoa(client.sin_addr));   
  242.         lpContext->m_nPort = client.sin_port;   
  243.            
  244.            
  245.         printf("create completion port key successful... \n");   
  246.            
  247.         //completion port 与socket关联起来    
  248.         if(!CreateIoCompletionPort((HANDLE)clientSocket,    
  249.             m_hIocp,    
  250.             (DWORD)lpContext,    
  251.             0))   
  252.         {   
  253.             PRINTDEBUG(WSAGetLastError());   
  254.             closesocket( lpContext->m_Socket );   
  255.             delete lpContext;   
  256.             continue;   
  257.         }   
  258.            
  259.         //初始化客户连接    
  260.         OVERLAPPEDPLUS  *pOlp = AllocateOverlappedPlus(OP_IOInitialize);   
  261.            
  262.         BOOL bSuccess = PostQueuedCompletionStatus(   
  263.             m_hIocp,    
  264.             0,   
  265.             (DWORD) lpContext,   
  266.             &pOlp->ol);   
  267.            
  268.         if ( (!bSuccess && GetLastError( ) != ERROR_IO_PENDING))   
  269.         {               
  270.             PRINTDEBUG(WSAGetLastError());   
  271.             closesocket( lpContext->m_Socket );   
  272.             delete lpContext;   
  273.             continue;   
  274.         }   
  275.            
  276.         printf("associate completion port and new client successful... \n");   
  277.            
  278.     }   
  279.     CloseCompletionPort();   
  280.     CloseHandle(m_hKillEvent);   
  281. }   
  282.    
  283.    
  284. //客户连接时初始化    
  285. BOOL CIOCPServer::OnClientInitializing(LPCLIENTCONTEXT lpContext, DWORD dwIoSize)   
  286. {   
  287. //  memset(lpContext->m_ip, 0, sizeof(lpContext->m_ip));    
  288.     printf("socket init from :%s:%d\n", lpContext->m_ip, lpContext->m_nPort);   
  289.        
  290.     return TRUE;   
  291. }   
  292.    
  293. //读客户数据,receive,如果接收到数据长度为0,则表示,客户端连接关闭    
  294. BOOL CIOCPServer::OnClientReading(LPCLIENTCONTEXT lpContext, DWORD dwIoSize)   
  295. {   
  296.     if(dwIoSize == 0)   
  297.     {   
  298.         FreeClientContext(lpContext);   
  299.         return FALSE;   
  300.     }   
  301.     printf("recv: %s\n", lpContext->m_wsaInBuffer.buf);   
  302.     printf("recv len: %d\n", dwIoSize);    
  303.    
  304.        
  305.     lpContext->m_ReadBuffer.Write(lpContext->m_byInBuffer,dwIoSize);   
  306.        
  307.     ProcessReceiveData(lpContext, lpContext->m_ReadBuffer);   
  308.     return TRUE;   
  309. }   
  310.    
  311. //写事件完成,但是CBuffer中的数据不一定都发送了!    
  312. BOOL CIOCPServer::OnClientWriting(LPCLIENTCONTEXT lpContext, DWORD dwIoSize)   
  313. {   
  314.     ULONG ulFlags = MSG_PARTIAL;   
  315.        
  316.     //删除已经发送了的数据    
  317.     lpContext->m_WriteBuffer.Delete(dwIoSize);   
  318.    
  319.     if (lpContext->m_WriteBuffer.GetBufferLen() == 0)   
  320.     {   
  321.         //数据都发送了!    
  322.    
  323.         //清除缓存          
  324.         lpContext->m_WriteBuffer.ClearBuffer();   
  325.         // 写事件完成了,可以允许下次写了    
  326.         SetEvent(lpContext->m_hWriteComplete);   
  327.    
  328.         printf("WRITE event completed \n");    
  329.     }   
  330.     else   
  331.     {   
  332.         LPOVERLAPPEDPLUS pOverlap = AllocateOverlappedPlus(OP_IOWrite);   
  333.            
  334.         lpContext->m_wsaOutBuffer.buf = lpContext->m_WriteBuffer.GetBuffer();   
  335.         lpContext->m_wsaOutBuffer.len = lpContext->m_WriteBuffer.GetBufferLen();   
  336.        
  337.         printf("data to sent: %s , length:%d\n",    
  338.             lpContext->m_wsaOutBuffer.buf,   
  339.             lpContext->m_wsaOutBuffer.len);   
  340.    
  341.         int nRetVal = WSASend(lpContext->m_Socket,    
  342.             &lpContext->m_wsaOutBuffer,   
  343.             1,   
  344.             &lpContext->m_wsaOutBuffer.len,    
  345.             ulFlags,   
  346.             &pOverlap->ol,    
  347.             NULL);   
  348.            
  349.         if ( nRetVal == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING )    
  350.         {   
  351.             FreeClientContext(lpContext);   
  352.         }          
  353.     }   
  354.        
  355.     return FALSE;//不等待读了!    
  356. }   
  357.    
  358. void CIOCPServer::FreeClientContext(LPCLIENTCONTEXT lpContext)   
  359. {   
  360.     if(ClientExit(lpContext))   
  361.     {   
  362.         //该用户的退出事件已经处理过,自己返回即可    
  363.         return ;   
  364.     }   
  365.    
  366.     CancelIo((HANDLE) lpContext->m_Socket);   
  367.        
  368.     closesocket( lpContext->m_Socket );   
  369.     lpContext->m_Socket = INVALID_SOCKET;   
  370.        
  371.     delete lpContext;   
  372. }   
  373.    
  374. //发送消息    
  375. void CIOCPServer::Send(LPCLIENTCONTEXT lpContext, CString strData)   
  376. {   
  377.     //将需要发送的数据添加入发送缓冲区      
  378.     lpContext->m_WriteBuffer.Write(strData);   
  379.    
  380.     printf("Waiting for WRITE event\n");   
  381.     WaitForSingleObject(lpContext->m_hWriteComplete, INFINITE);   
  382.    
  383.     //准备发送数据    
  384.     lpContext->m_wsaOutBuffer.buf = lpContext->m_WriteBuffer.GetBuffer();   
  385.     lpContext->m_wsaOutBuffer.len = lpContext->m_WriteBuffer.GetBufferLen();   
  386.        
  387.     LPOVERLAPPEDPLUS lpOverlap = AllocateOverlappedPlus(OP_IOWrite);   
  388.     PostQueuedCompletionStatus(m_hIocp, 0, (DWORD) lpContext, &lpOverlap->ol);      
  389. }   
  390.    
  391. // IOCPServer.cpp: implementation of the CIOCPServer class.    
  392. //    
  393. //    
  394. #include "stdafx.h"    
  395. #include "IOCPServer.h"    
  396. //    
  397. // Construction/Destruction    
  398. //    
  399. CIOCPServer::CIOCPServer()   
  400. {   
  401.     //socket初始化    
  402.     WSADATA wsd;   
  403.     WORD wVersionRequested = MAKEWORD(2, 2);   
  404.     int nResult = WSAStartup(wVersionRequested, &wsd);   
  405.     if (nResult == SOCKET_ERROR)   
  406.     {   
  407.         WSACleanup();   
  408.         PRINTDEBUG(WSAGetLastError());   
  409.     }   
  410.        
  411.     if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2)   
  412.     {   
  413.         WSACleanup();   
  414.     }   
  415.        
  416.     m_hKillEvent = CreateEvent(NULL, TRUE, FALSE, NULL);   
  417.     printf("socket init successful... \n");   
  418. }   
  419.    
  420. CIOCPServer::~CIOCPServer()   
  421. {   
  422.     WSACleanup();   
  423. }   
  424.    
  425. //分配连接overlappedplus    
  426. LPOVERLAPPEDPLUS  CIOCPServer::AllocateOverlappedPlus(IOType ioType)   
  427. {   
  428.     OVERLAPPEDPLUS* pOlp = NULL;   
  429.        
  430.     pOlp = new OVERLAPPEDPLUS;   
  431.     ZeroMemory(pOlp, sizeof(OVERLAPPEDPLUS));   
  432.     pOlp->opCode = ioType;   
  433.        
  434.     return pOlp;       
  435. }   
  436.    
  437. //分配连接进入的客户的相关信息    
  438. LPCLIENTCONTEXT  CIOCPServer::AllocateContext()   
  439. {   
  440.     LPCLIENTCONTEXT lpContext = NULL;   
  441.        
  442.     lpContext = new CLIENTCONTEXT;   
  443.     ZeroMemory(lpContext, sizeof(CLIENTCONTEXT));   
  444.     lpContext->m_wsaInBuffer.buf = lpContext->m_byInBuffer;   
  445.     lpContext->m_wsaInBuffer.len = BUFSIZE;   
  446.    
  447.     lpContext->m_hWriteComplete = CreateEvent(NULL, FALSE, TRUE, NULL);   
  448.    
  449.     return lpContext;      
  450. }   
  451.    
  452. //释放overlappedplus    
  453. void  CIOCPServer::FreeOverlappedPlus(LPOVERLAPPEDPLUS lpOlp)   
  454. {   
  455.     delete lpOlp;      
  456. }   
  457.    
  458. //根据消息overlapped的类型,处理消息,返回值TRUE:继续读,FALSE,不读    
  459. //一般写事件就不让他都返回FALSE,没有必要再读了!    
  460. BOOL CIOCPServer::ProcessIOMessage(IOType opCode, LPCLIENTCONTEXT lpContext , DWORD dwIoSize)   
  461. {   
  462.     BOOL bRet = FALSE;     
  463.     //根据opCode确定操作    
  464.     switch (opCode)   
  465.     {   
  466.     case OP_IOInitialize:   
  467.         bRet = OnClientInitializing(lpContext, dwIoSize);   
  468.         break;   
  469.     case OP_IORead:   
  470.         bRet = OnClientReading(lpContext, dwIoSize);   
  471.         break;   
  472.     case OP_IOWrite:   
  473.         bRet = OnClientWriting(lpContext, dwIoSize);   
  474.         break;   
  475.     default:   
  476.         printf("worker thread:unknown operation...\n");   
  477.     }   
  478.     return bRet;    
  479. }   
  480.    
  481. //关闭完成端口    
  482. void CIOCPServer::CloseCompletionPort( )   
  483. {   
  484.     PostQueuedCompletionStatus(m_hIocp, 0, (DWORD) NULL, NULL);    
  485.     // Close the CompletionPort and stop any more requests    
  486.     CloseHandle(m_hIocp);      
  487. }   
  488.    
  489. void CIOCPServer::CreateWorkerThread()   
  490. {   
  491.     SYSTEM_INFO sysinfo;   
  492.     DWORD dwThreadId;   
  493.        
  494.     //在completion port上等待的线程数为:CPU*2+2    
  495.     GetSystemInfo(&sysinfo);   
  496.     m_dwThreads  = sysinfo.dwNumberOfProcessors*2+2;   
  497.        
  498.     printf("create worker thread num: %d \n", m_dwThreads);   
  499.     for(UINT i=0;i<M_DWTHREADS;I++) bResult="GetQueuedCompletionStatus(pIocpServer-" BOOL bEnterRead="TRUE;" bError="FALSE;" { (TRUE) while lpOlp; LPOVERLAPPEDPLUS lpOverlapped; LPWSAOVERLAPPED lpContext; LPCLIENTCONTEXT dwNumRead; DWORD *)lpParam; *pIocpServer="(CIOCPServer" CIOCPServer lpParam) * void CIOCPServer::CompletionWorkerThread( WINAPI 绑定在端口上工作线程 } CloseHandle(hThread); &dwThreadId); 0, (LPVOID)this, CompletionWorkerThread, hThread="CreateThread(NULL," hThread; HANDLE>m_hIocp,    
  500.             &dwNumRead,   
  501.             (LPDWORD)&lpContext,   
  502.             &lpOverlapped,   
  503.             INFINITE);   
  504.            
  505.         //获得LPOVERLAPPEDPLUS指针    
  506.         lpOlp = CONTAINING_RECORD(lpOverlapped, OVERLAPPEDPLUS, ol);   
  507.         printf("Event comming %d\n", lpOlp->opCode);   
  508.            
  509.         //非timeout引起的错误, 相关信息没有从GetQueuedCompletionStatus中返回    
  510.         if (!bResult && lpOlp == NULL && WAIT_TIMEOUT != WSAGetLastError())   
  511.         {   
  512.             PRINTDEBUG(WSAGetLastError());   
  513.             // 发生错误    
  514.             bError = TRUE;   
  515.         }   
  516.         //错误,但是相关信息从GetQueuedCompletionStatus中返回    
  517.         //可能原因之一是:客户强制退出了!    
  518.         else if(!bResult && lpOlp != NULL)   
  519.         {   
  520.             PRINTDEBUG(WSAGetLastError());   
  521.             pIocpServer->FreeClientContext(lpContext);   
  522.             //循环继续,不应该读了!    
  523.             continue;   
  524.         }   
  525.    
  526.         //无错误,处理事件    
  527.         if (!bError)    
  528.         {   
  529.             if(bResult && NULL != lpOlp && NULL != lpContext)    
  530.             {   
  531.                 bEnterRead = pIocpServer->ProcessIOMessage(lpOlp->opCode, lpContext, dwNumRead);   
  532.             }   
  533.         }   
  534.            
  535.         //无错 && 读    
  536.         if(! bError && bEnterRead)    
  537.         {   
  538.             LPOVERLAPPEDPLUS lpOlp = pIocpServer->AllocateOverlappedPlus(OP_IORead);   
  539.             ULONG           ulFlags = MSG_PARTIAL;   
  540.                
  541.             ZeroMemory(lpContext->m_wsaInBuffer.buf, lpContext->m_wsaInBuffer.len);   
  542.             UINT nRetVal = WSARecv(lpContext->m_Socket,    
  543.                 &lpContext->m_wsaInBuffer,   
  544.                 1,   
  545.                 &dwNumRead,    
  546.                 &ulFlags,   
  547.                 &lpOlp->ol,    
  548.                 NULL);   
  549.    
  550.             if ( nRetVal == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)    
  551.             {   
  552.                 printf("CLIENT abortive exit\n");   
  553.                 pIocpServer->FreeClientContext(lpContext);   
  554.             }   
  555.    
  556.         }          
  557.            
  558.         pIocpServer->FreeOverlappedPlus(lpOlp);   
  559.            
  560.     }   
  561.     return 0;   
  562. }   
  563.    
  564. BOOL CIOCPServer::Initialize(DWORD conns, int port)   
  565. {   
  566.     m_sListen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);   
  567.     if(m_sListen == SOCKET_ERROR)   
  568.     {   
  569.         PRINTDEBUG(WSAGetLastError());   
  570.         return FALSE;   
  571.     }   
  572.        
  573.     printf("create listening socket successful... \n");   
  574.        
  575.     //需要绑定的本地地址    
  576.     sockaddr_in local;   
  577.     memset(&local, 0, sizeof(local));   
  578.     local.sin_addr.s_addr = htonl(INADDR_ANY);     
  579.     local.sin_family = AF_INET;   
  580.     local.sin_port = htons(port);   
  581.        
  582.     //绑定,将监听端口绑定到本地地址    
  583.     if(bind(m_sListen, (sockaddr*)&local,sizeof(local))   
  584.         == SOCKET_ERROR)   
  585.     {   
  586.         PRINTDEBUG(WSAGetLastError());   
  587.         return FALSE;   
  588.     }   
  589.        
  590.     printf("bind local socket successful... \n");   
  591.        
  592.     //产生完成端口    
  593.     m_hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);   
  594.     if(m_hIocp == NULL)   
  595.     {   
  596.         PRINTDEBUG(WSAGetLastError());   
  597.         return FALSE;   
  598.     }   
  599.        
  600.     printf("create completion port successful... \n");   
  601.    
  602.     CreateWorkerThread();   
  603.     printf("listening socket... \n");   
  604.     //监听线程    
  605.     listen(m_sListen, conns);   
  606.    
  607.     return TRUE;   
  608. }   
  609.    
  610. void CIOCPServer::Accept()   
  611. {   
  612.     sockaddr_in client;   
  613.     int sClientLength = sizeof(client);   
  614.     while (WAIT_TIMEOUT == WaitForSingleObject(m_hKillEvent, 0))   
  615.     {   
  616.         printf("waiting for client connecting... \n");   
  617.            
  618.         //等待客户连接    
  619.         SOCKET clientSocket = accept(m_sListen, (sockaddr*)&client, &sClientLength);   
  620.         if(clientSocket == SOCKET_ERROR)   
  621.         {   
  622.             PRINTDEBUG(WSAGetLastError());     
  623.             continue;   
  624.         }   
  625.            
  626.         printf("a new client comming... \n");   
  627.            
  628.         //设置completion key    
  629.         LPCLIENTCONTEXT lpContext = AllocateContext();   
  630.         lpContext->m_Socket = clientSocket;         
  631.         sprintf(lpContext->m_ip,inet_ntoa(client.sin_addr));   
  632.         lpContext->m_nPort = client.sin_port;   
  633.            
  634.            
  635.         printf("create completion port key successful... \n");   
  636.            
  637.         //completion port 与socket关联起来    
  638.         if(!CreateIoCompletionPort((HANDLE)clientSocket,    
  639.             m_hIocp,    
  640.             (DWORD)lpContext,    
  641.             0))   
  642.         {   
  643.             PRINTDEBUG(WSAGetLastError());   
  644.             closesocket( lpContext->m_Socket );   
  645.             delete lpContext;   
  646.             continue;   
  647.         }   
  648.            
  649.         //初始化客户连接    
  650.         OVERLAPPEDPLUS  *pOlp = AllocateOverlappedPlus(OP_IOInitialize);   
  651.            
  652.         BOOL bSuccess = PostQueuedCompletionStatus(   
  653.             m_hIocp,    
  654.             0,   
  655.             (DWORD) lpContext,   
  656.             &pOlp->ol);   
  657.            
  658.         if ( (!bSuccess && GetLastError( ) != ERROR_IO_PENDING))   
  659.         {               
  660.             PRINTDEBUG(WSAGetLastError());   
  661.             closesocket( lpContext->m_Socket );   
  662.             delete lpContext;   
  663.             continue;   
  664.         }   
  665.            
  666.         printf("associate completion port and new client successful... \n");   
  667.            
  668.     }   
  669.     CloseCompletionPort();   
  670.     CloseHandle(m_hKillEvent);   
  671. }   
  672.    
  673.    
  674. //客户连接时初始化    
  675. BOOL CIOCPServer::OnClientInitializing(LPCLIENTCONTEXT lpContext, DWORD dwIoSize)   
  676. {   
  677. //  memset(lpContext->m_ip, 0, sizeof(lpContext->m_ip));    
  678.     printf("socket init from :%s:%d\n", lpContext->m_ip, lpContext->m_nPort);   
  679.        
  680.     return TRUE;   
  681. }   
  682.    
  683. //读客户数据,receive,如果接收到数据长度为0,则表示,客户端连接关闭    
  684. BOOL CIOCPServer::OnClientReading(LPCLIENTCONTEXT lpContext, DWORD dwIoSize)   
  685. {   
  686.     if(dwIoSize == 0)   
  687.     {   
  688.         FreeClientContext(lpContext);   
  689.         return FALSE;   
  690.     }   
  691.     printf("recv: %s\n", lpContext->m_wsaInBuffer.buf);   
  692.     printf("recv len: %d\n", dwIoSize);    
  693.    
  694.        
  695.     lpContext->m_ReadBuffer.Write(lpContext->m_byInBuffer,dwIoSize);   
  696.        
  697.     ProcessReceiveData(lpContext, lpContext->m_ReadBuffer);   
  698.     return TRUE;   
  699. }   
  700.    
  701. //写事件完成,但是CBuffer中的数据不一定都发送了!    
  702. BOOL CIOCPServer::OnClientWriting(LPCLIENTCONTEXT lpContext, DWORD dwIoSize)   
  703. {   
  704.     ULONG ulFlags = MSG_PARTIAL;   
  705.        
  706.     //删除已经发送了的数据    
  707.     lpContext->m_WriteBuffer.Delete(dwIoSize);   
  708.    
  709.     if (lpContext->m_WriteBuffer.GetBufferLen() == 0)   
  710.     {   
  711.         //数据都发送了!    
  712.    
  713.         //清除缓存          
  714.         lpContext->m_WriteBuffer.ClearBuffer();   
  715.         // 写事件完成了,可以允许下次写了    
  716.         SetEvent(lpContext->m_hWriteComplete);   
  717.    
  718.         printf("WRITE event completed \n");    
  719.     }   
  720.     else   
  721.     {   
  722.         LPOVERLAPPEDPLUS pOverlap = AllocateOverlappedPlus(OP_IOWrite);   
  723.            
  724.         lpContext->m_wsaOutBuffer.buf = lpContext->m_WriteBuffer.GetBuffer();   
  725.         lpContext->m_wsaOutBuffer.len = lpContext->m_WriteBuffer.GetBufferLen();   
  726.        
  727.         printf("data to sent: %s , length:%d\n",    
  728.             lpContext->m_wsaOutBuffer.buf,   
  729.             lpContext->m_wsaOutBuffer.len);   
  730.    
  731.         int nRetVal = WSASend(lpContext->m_Socket,    
  732.             &lpContext->m_wsaOutBuffer,   
  733.             1,   
  734.             &lpContext->m_wsaOutBuffer.len,    
  735.             ulFlags,   
  736.             &pOverlap->ol,    
  737.             NULL);   
  738.            
  739.         if ( nRetVal == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING )    
  740.         {   
  741.             FreeClientContext(lpContext);   
  742.         }          
  743.     }   
  744.        
  745.     return FALSE;//不等待读了!    
  746. }   
  747.    
  748. void CIOCPServer::FreeClientContext(LPCLIENTCONTEXT lpContext)   
  749. {   
  750.     if(ClientExit(lpContext))   
  751.     {   
  752.         //该用户的退出事件已经处理过,自己返回即可    
  753.         return ;   
  754.     }   
  755.    
  756.     CancelIo((HANDLE) lpContext->m_Socket);   
  757.        
  758.     closesocket( lpContext->m_Socket );   
  759.     lpContext->m_Socket = INVALID_SOCKET;   
  760.        
  761.     delete lpContext;   
  762. }   
  763.    
  764. //发送消息    
  765. void CIOCPServer::Send(LPCLIENTCONTEXT lpContext, CString strData)   
  766. {   
  767.     //将需要发送的数据添加入发送缓冲区      
  768.     lpContext->m_WriteBuffer.Write(strData);   
  769.    
  770.     printf("Waiting for WRITE event\n");   
  771.     WaitForSingleObject(lpContext->m_hWriteComplete, INFINITE);   
  772.    
  773.     //准备发送数据    
  774.     lpContext->m_wsaOutBuffer.buf = lpContext->m_WriteBuffer.GetBuffer();   
  775.     lpContext->m_wsaOutBuffer.len = lpContext->m_WriteBuffer.GetBufferLen();   
  776.        
  777.     LPOVERLAPPEDPLUS lpOverlap = AllocateOverlappedPlus(OP_IOWrite);   
  778.     PostQueuedCompletionStatus(m_hIocp, 0, (DWORD) lpContext, &lpOverlap->ol);      
  779. }   
  780.    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值