Winsock IOCP模型

view plain copy to clipboard print ?
  1. // IOCP2.cpp : Defines the entry point for the console application.   
  2. //   
  3.   
  4. #include "stdafx.h"   
  5. #include <WinSock2.h>   
  6. #include <MSWSock.h>   
  7. #include <Windows.h>   
  8. #include <process.h>   
  9. #pragma comment(lib, "WS2_32.lib")   
  10.   
  11. #define MAX_BUFFER  256   
  12. #define MAX_TIMEOUT 1000   
  13. #define MAX_SOCKET  1024   
  14. #define MAX_THREAD  64   
  15. #define MAX_ACCEPT  5   
  16.   
  17. typedef   enum  _OPERATION_INFO_  
  18. {  
  19.     OP_NULL,  
  20.     OP_ACCEPT,  
  21.     OP_READ,  
  22.     OP_WRITE  
  23. }OPERATIONINFO;  
  24.   
  25. typedef   struct  _PER_HANDLE_DATA_  
  26. {  
  27. public :  
  28.     _PER_HANDLE_DATA_()  
  29.     {  
  30.         clean();  
  31.     }  
  32.     ~_PER_HANDLE_DATA_()  
  33.     {  
  34.         clean();  
  35.     }  
  36. protected :  
  37.     void  clean()  
  38.     {  
  39.         sock = INVALID_SOCKET;  
  40.         memset(&addr, 0, sizeof (addr));  
  41.         addr.sin_addr.S_un.S_addr = INADDR_ANY;  
  42.         addr.sin_port = htons(0);  
  43.         addr.sin_family = AF_INET;  
  44.     }  
  45. public :   
  46.     SOCKET sock;  
  47.     SOCKADDR_IN addr;  
  48. }PERHANDLEDATA, *PPERHANDLEDATA;  
  49.   
  50. typedef   struct  _PER_IO_DTATA_  
  51. {  
  52. public :   
  53.     _PER_IO_DTATA_()  
  54.     {  
  55.         clean();  
  56.     }  
  57.     ~_PER_IO_DTATA_()  
  58.     {  
  59.         clean();  
  60.     }  
  61.     void  clean()  
  62.     {  
  63.         ZeroMemory(&ol, sizeof (ol));  
  64.         memset(buf, 0, sizeof (buf));  
  65.         sAccept = INVALID_SOCKET;  
  66.         sListen = INVALID_SOCKET;  
  67.         wsaBuf.buf = buf;  
  68.         wsaBuf.len = MAX_BUFFER;  
  69.         opType =  OP_NULL;  
  70.     }  
  71. public :  
  72.     WSAOVERLAPPED ol;  
  73.     SOCKET sAccept; // Only valid with AcceptEx   
  74.     SOCKET sListen; // Only valid with AcceptEx   
  75.     WSABUF wsaBuf;  
  76.     char  buf[MAX_BUFFER];  
  77.     OPERATIONINFO opType;  
  78. }PERIODATA, *PPERIODATA;  
  79.   
  80. HANDLE  hThread[MAX_THREAD] = {0};  
  81. PERIODATA* pAcceptData[MAX_ACCEPT] = {0};  
  82. int  g_nThread = 0;  
  83. BOOL  g_bExitThread = FALSE;  
  84. LPFN_ACCEPTEX lpfnAcceptEx = NULL;  
  85. LPFN_GETACCEPTEXSOCKADDRS lpfnGetAcceptExSockAddrs = NULL;  
  86. GUID GuidAcceptEx = WSAID_ACCEPTEX;  
  87. GUID GuidGetAcceptExSockAddrs = WSAID_GETACCEPTEXSOCKADDRS;  
  88.   
  89. unsigned __stdcall ThreadProc(LPVOID  lParam);  
  90. BOOL  PostAccept(PERIODATA* pIoData);  
  91.   
  92. int  _tmain( int  argc, _TCHAR* argv[])  
  93. {  
  94.     WORD  wVersionRequested = MAKEWORD(2, 2);  
  95.     WSADATA wsaData;  
  96.     if (0 != WSAStartup(wVersionRequested, &wsaData))  
  97.     {  
  98.         printf("WSAStartup failed with error code: %d/n" , GetLastError());  
  99.         return  EXIT_FAILURE;  
  100.     }  
  101.   
  102.     if (2 != HIBYTE(wsaData.wVersion) || 2 != LOBYTE(wsaData.wVersion))  
  103.     {  
  104.         printf("Socket version not supported./n" );  
  105.         WSACleanup();  
  106.         return  EXIT_FAILURE;  
  107.     }  
  108.   
  109.     // Create IOCP   
  110.     HANDLE  hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);  
  111.     if (NULL == hIOCP)  
  112.     {  
  113.         printf("CreateIoCompletionPort failed with error code: %d/n" , WSAGetLastError());  
  114.         WSACleanup();  
  115.         return  EXIT_FAILURE;  
  116.     }  
  117.   
  118.     // Create worker thread   
  119.     SYSTEM_INFO si = {0};  
  120.     GetSystemInfo(&si);  
  121.     for ( int  i = 0; i < ( int )si.dwNumberOfProcessors+2; i++)  
  122.     {  
  123.         hThread[g_nThread] = (HANDLE )_beginthreadex(NULL, 0, ThreadProc, ( LPVOID )hIOCP, 0, NULL);  
  124.         if (NULL == hThread[g_nThread])  
  125.         {  
  126.             printf("_beginthreadex failed with error code: %d/n" , GetLastError());  
  127.             continue ;  
  128.         }  
  129.         ++g_nThread;  
  130.   
  131.         if (g_nThread > MAX_THREAD)  
  132.         {  
  133.             break ;  
  134.         }  
  135.     }  
  136.   
  137.     // Create listen SOCKET   
  138.     SOCKET sListen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);  
  139.     if (INVALID_SOCKET == sListen)  
  140.     {  
  141.         printf("WSASocket failed with error code: %d/n" , WSAGetLastError());  
  142.         goto  EXIT_CODE;  
  143.     }  
  144.   
  145.     // Associate SOCKET with IOCP   
  146.     if (NULL == CreateIoCompletionPort(( HANDLE )sListen, hIOCP, NULL, 0))  
  147.     {  
  148.         printf("CreateIoCompletionPort failed with error code: %d/n" , WSAGetLastError());  
  149.         if (INVALID_SOCKET != sListen)  
  150.         {  
  151.             closesocket(sListen);  
  152.             sListen = INVALID_SOCKET;  
  153.         }  
  154.         goto  EXIT_CODE;  
  155.     }  
  156.   
  157.     // Bind SOCKET   
  158.     SOCKADDR_IN addr;  
  159.     memset(&addr, 0, sizeof (addr));  
  160.     addr.sin_family = AF_INET;  
  161.     addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1" );  
  162.     addr.sin_port = htons(5050);  
  163.     if (SOCKET_ERROR == bind(sListen, (LPSOCKADDR)&addr,  sizeof (addr)))  
  164.     {  
  165.         printf("bind failed with error code: %d/n" , WSAGetLastError());  
  166.         if (INVALID_SOCKET != sListen)  
  167.         {  
  168.             closesocket(sListen);  
  169.             sListen = INVALID_SOCKET;  
  170.         }  
  171.         goto  EXIT_CODE;  
  172.     }  
  173.   
  174.     // Start Listen   
  175.     if (SOCKET_ERROR == listen(sListen, 200))  
  176.     {  
  177.         printf("listen failed with error code: %d/n" , WSAGetLastError());  
  178.         if (INVALID_SOCKET != sListen)  
  179.         {  
  180.             closesocket(sListen);  
  181.             sListen = INVALID_SOCKET;  
  182.         }  
  183.         goto  EXIT_CODE;  
  184.     }  
  185.   
  186.     printf("Server start, wait for client to connect .../n" );  
  187.   
  188.     DWORD  dwBytes = 0;  
  189.     if (SOCKET_ERROR == WSAIoctl(sListen, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx,  sizeof (GuidAcceptEx), &lpfnAcceptEx,  
  190.         sizeof (lpfnAcceptEx), &dwBytes, NULL, NULL))  
  191.     {  
  192.         printf("WSAIoctl failed with error code: %d/n" , WSAGetLastError());  
  193.         if (INVALID_SOCKET != sListen)  
  194.         {  
  195.             closesocket(sListen);  
  196.             sListen = INVALID_SOCKET;  
  197.         }  
  198.         goto  EXIT_CODE;  
  199.     }  
  200.   
  201.     if (SOCKET_ERROR == WSAIoctl(sListen, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidGetAcceptExSockAddrs,   
  202.         sizeof (GuidGetAcceptExSockAddrs), &lpfnGetAcceptExSockAddrs,  sizeof (lpfnGetAcceptExSockAddrs),   
  203.         &dwBytes, NULL, NULL))  
  204.     {  
  205.         printf("WSAIoctl failed with error code: %d/n" , WSAGetLastError());  
  206.         if (INVALID_SOCKET != sListen)  
  207.         {  
  208.             closesocket(sListen);  
  209.             sListen = INVALID_SOCKET;  
  210.         }  
  211.         goto  EXIT_CODE;  
  212.     }  
  213.   
  214.     // Post MAX_ACCEPT accept   
  215.     for ( int  i=0; i<MAX_ACCEPT; i++)  
  216.     {  
  217.         pAcceptData[i] = new  PERIODATA;  
  218.         pAcceptData[i]->sListen = sListen;  
  219.         PostAccept(pAcceptData[i]);  
  220.     }  
  221.     // After 1 hour later, Server shutdown.   
  222.     Sleep(1000 * 60 *60);  
  223.   
  224. EXIT_CODE:  
  225.     g_bExitThread = TRUE;  
  226.   
  227.     PostQueuedCompletionStatus(hIOCP, 0, NULL, NULL);  
  228.     WaitForMultipleObjects(g_nThread, hThread, TRUE, INFINITE);  
  229.     for ( int  i = 0; i < g_nThread; i++)  
  230.     {  
  231.         CloseHandle(hThread[g_nThread]);  
  232.     }  
  233.   
  234.     for ( int  i=0; i<MAX_ACCEPT; i++)  
  235.     {  
  236.         if (pAcceptData[i])  
  237.         {  
  238.             delete  pAcceptData[i];  
  239.             pAcceptData[i] = NULL;  
  240.         }  
  241.     }  
  242.   
  243.     if (INVALID_SOCKET != sListen)  
  244.     {  
  245.         closesocket(sListen);  
  246.         sListen = INVALID_SOCKET;  
  247.     }  
  248.     CloseHandle(hIOCP); // Close IOCP   
  249.   
  250.     WSACleanup();  
  251.     return  0;  
  252. }  
  253.   
  254. BOOL  PostAccept(PERIODATA* pIoData)  
  255. {  
  256.     if (INVALID_SOCKET == pIoData->sListen)  
  257.     {  
  258.         return  FALSE;  
  259.     }  
  260.   
  261.     DWORD  dwBytes = 0;  
  262.     pIoData->opType = OP_ACCEPT;  
  263.     pIoData->sAccept = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);  
  264.     if (INVALID_SOCKET == pIoData->sAccept)  
  265.     {  
  266.         printf("WSASocket failed with error code: %d/n" , WSAGetLastError());  
  267.         return  FALSE;  
  268.     }  
  269.   
  270.     if (FALSE == lpfnAcceptEx(pIoData->sListen, pIoData->sAccept, pIoData->wsaBuf.buf, pIoData->wsaBuf.len - (( sizeof (SOCKADDR_IN)+16)*2),   
  271.         sizeof (SOCKADDR_IN)+16,  sizeof (SOCKADDR_IN)+16, &dwBytes, &(pIoData->ol)))  
  272.     {  
  273.         if (WSA_IO_PENDING != WSAGetLastError())  
  274.         {  
  275.             printf("lpfnAcceptEx failed with error code: %d/n" , WSAGetLastError());  
  276.   
  277.             return  FALSE;  
  278.         }  
  279.     }  
  280.     return  TRUE;  
  281. }  
  282.   
  283. unsigned __stdcall ThreadProc(LPVOID  lParam)  
  284. {  
  285.     HANDLE  hIOCP = ( HANDLE )lParam;  
  286.   
  287.     PERHANDLEDATA* pPerHandleData = NULL;  
  288.     PERIODATA* pPerIoData = NULL;  
  289.     WSAOVERLAPPED* lpOverlapped = NULL;  
  290.     DWORD  dwTrans = 0;  
  291.     DWORD  dwFlags = 0;  
  292.     while (!g_bExitThread)  
  293.     {  
  294.         BOOL  bRet = GetQueuedCompletionStatus(hIOCP, &dwTrans, ( PULONG_PTR )&pPerHandleData, &lpOverlapped, MAX_TIMEOUT);  
  295.         if (!bRet)  
  296.         {  
  297.             // Timeout and exit thread   
  298.             if (WAIT_TIMEOUT == GetLastError())  
  299.             {  
  300.                 continue ;  
  301.             }  
  302.             // Error   
  303.             printf("GetQueuedCompletionStatus failed with error: %d/n" , GetLastError());  
  304.             continue ;  
  305.         }  
  306.         else   
  307.         {  
  308.             pPerIoData = CONTAINING_RECORD(lpOverlapped, PERIODATA, ol);  
  309.             if (NULL == pPerIoData)  
  310.             {  
  311.                 // Exit thread   
  312.                 break ;  
  313.             }  
  314.   
  315.             if ((0 == dwTrans) && (OP_READ == pPerIoData->opType || OP_WRITE == pPerIoData->opType))  
  316.             {  
  317.                 // Client leave.   
  318.                 printf("Client: <%s : %d> leave./n" , inet_ntoa(pPerHandleData->addr.sin_addr), ntohs(pPerHandleData->addr.sin_port));  
  319.                 closesocket(pPerHandleData->sock);  
  320.                 delete  pPerHandleData;  
  321.                 delete  pPerIoData;  
  322.                 continue ;  
  323.             }  
  324.             else   
  325.             {  
  326.                 switch (pPerIoData->opType)  
  327.                 {  
  328.                 case  OP_ACCEPT:  // Accept   
  329.                     {     
  330.                         SOCKADDR_IN* remote = NULL;  
  331.                         SOCKADDR_IN* local = NULL;  
  332.                         int  remoteLen =  sizeof (SOCKADDR_IN);  
  333.                         int  localLen =  sizeof (SOCKADDR_IN);  
  334.                         lpfnGetAcceptExSockAddrs(pPerIoData->wsaBuf.buf, pPerIoData->wsaBuf.len - ((sizeof (SOCKADDR_IN)+16)*2),  
  335.                             sizeof (SOCKADDR_IN)+16,  sizeof (SOCKADDR_IN)+16, (LPSOCKADDR*)&local, &localLen, (LPSOCKADDR*)&remote, &remoteLen);  
  336.                         printf("Client <%s : %d> come in./n" , inet_ntoa(remote->sin_addr), ntohs(remote->sin_port));  
  337.                         printf("Recv Data: <%s : %d> %s./n" , inet_ntoa(remote->sin_addr), ntohs(remote->sin_port), pPerIoData->wsaBuf.buf);  
  338.   
  339.                         if (NULL != pPerHandleData)  
  340.                         {  
  341.                             delete  pPerHandleData;  
  342.                             pPerHandleData = NULL;  
  343.                         }  
  344.                         pPerHandleData = new  PERHANDLEDATA;  
  345.                         pPerHandleData->sock = pPerIoData->sAccept;  
  346.   
  347.                         PERHANDLEDATA* pPerHandle = new  PERHANDLEDATA;  
  348.                         pPerHandle->sock = pPerIoData->sAccept;  
  349.                         PERIODATA* pPerIo = new  PERIODATA;  
  350.                         pPerIo->opType = OP_WRITE;  
  351.                         strcpy_s(pPerIo->buf, MAX_BUFFER, pPerIoData->buf);  
  352.                         DWORD  dwTrans = strlen(pPerIo->buf);  
  353.                         memcpy(&(pPerHandleData->addr), remote, sizeof (SOCKADDR_IN));  
  354.                         // Associate with IOCP   
  355.                         if (NULL == CreateIoCompletionPort(( HANDLE )(pPerHandleData->sock), hIOCP, ( ULONG_PTR )pPerHandleData, 0))  
  356.                         {  
  357.                             printf("CreateIoCompletionPort failed with error code: %d/n" , GetLastError());  
  358.                             closesocket(pPerHandleData->sock);  
  359.                             delete  pPerHandleData;  
  360.                             continue ;  
  361.                         }  
  362.   
  363.                         // Post Accept   
  364.                         memset(&(pPerIoData->ol), 0, sizeof (pPerIoData->ol));  
  365.                         PostAccept(pPerIoData);  
  366.   
  367.                         // Post Receive                        
  368.                         DWORD  dwFlags = 0;  
  369.                         if (SOCKET_ERROR == WSASend(pPerHandle->sock, &(pPerIo->wsaBuf), 1,   
  370.                             &dwTrans, dwFlags, &(pPerIo->ol), NULL))  
  371.                         {  
  372.                             if (WSA_IO_PENDING != WSAGetLastError())  
  373.                             {  
  374.                                 printf("WSASend failed with error code: %d/n" , WSAGetLastError());  
  375.                                 closesocket(pPerHandle->sock);  
  376.                                 delete  pPerHandle;  
  377.                                 delete  pPerIo;  
  378.                                 continue ;  
  379.                             }  
  380.                         }  
  381.                     }  
  382.                     break ;  
  383.   
  384.                 case  OP_READ:  // Read   
  385.                     printf("recv client <%s : %d> data: %s/n" , inet_ntoa(pPerHandleData->addr.sin_addr), ntohs(pPerHandleData->addr.sin_port), pPerIoData->buf);  
  386.                     pPerIoData->opType = OP_WRITE;  
  387.                     memset(&(pPerIoData->ol), 0, sizeof (pPerIoData->ol));  
  388.                     if (SOCKET_ERROR == WSASend(pPerHandleData->sock, &(pPerIoData->wsaBuf), 1, &dwTrans, dwFlags, &(pPerIoData->ol), NULL))  
  389.                     {  
  390.                         if (WSA_IO_PENDING != WSAGetLastError())  
  391.                         {  
  392.                             printf("WSASend failed with error code: %d./n" , WSAGetLastError());  
  393.                             continue ;  
  394.                         }  
  395.                     }  
  396.                     break ;  
  397.   
  398.                 case  OP_WRITE:  // Write   
  399.                     {  
  400.                         pPerIoData->opType = OP_READ;  
  401.                         dwFlags = 0;  
  402.                         memset(&(pPerIoData->ol), 0, sizeof (pPerIoData->ol));  
  403.                         memset(pPerIoData->buf, 0, sizeof (pPerIoData->buf));  
  404.                         pPerIoData->wsaBuf.buf = pPerIoData->buf;  
  405.                         dwTrans = pPerIoData->wsaBuf.len = MAX_BUFFER;  
  406.                         if (SOCKET_ERROR == WSARecv(pPerHandleData->sock, &(pPerIoData->wsaBuf), 1, &dwTrans, &dwFlags, &(pPerIoData->ol), NULL))  
  407.                         {  
  408.                             if (WSA_IO_PENDING != WSAGetLastError())  
  409.                             {  
  410.                                 printf("WSARecv failed with error code: %d./n" , WSAGetLastError());  
  411.                                 continue ;  
  412.                             }  
  413.                         }  
  414.                     }  
  415.                     break ;  
  416.   
  417.                 default :  
  418.                     break ;  
  419.                 }  
  420.             }  
  421.         }  
  422.     }  
  423.     return  0;  

你可能感兴趣的:(thread,IO,socket,null,buffer,extension)