Winsock IOCP模型

    技术2022-05-20  30

    view plain copy to clipboard print ? // IOCP2.cpp : Defines the entry point for the console application.    //       #include "stdafx.h"    #include <WinSock2.h>    #include <MSWSock.h>    #include <Windows.h>    #include <process.h>    #pragma comment(lib, "WS2_32.lib")       #define MAX_BUFFER  256    #define MAX_TIMEOUT 1000    #define MAX_SOCKET  1024    #define MAX_THREAD  64    #define MAX_ACCEPT  5       typedef   enum  _OPERATION_INFO_   {       OP_NULL,       OP_ACCEPT,       OP_READ,       OP_WRITE   }OPERATIONINFO;      typedef   struct  _PER_HANDLE_DATA_   {   public :       _PER_HANDLE_DATA_()       {           clean();       }       ~_PER_HANDLE_DATA_()       {           clean();       }   protected :       void  clean()       {           sock = INVALID_SOCKET;           memset(&addr, 0, sizeof (addr));           addr.sin_addr.S_un.S_addr = INADDR_ANY;           addr.sin_port = htons(0);           addr.sin_family = AF_INET;       }   public :        SOCKET sock;       SOCKADDR_IN addr;   }PERHANDLEDATA, *PPERHANDLEDATA;      typedef   struct  _PER_IO_DTATA_   {   public :        _PER_IO_DTATA_()       {           clean();       }       ~_PER_IO_DTATA_()       {           clean();       }       void  clean()       {           ZeroMemory(&ol, sizeof (ol));           memset(buf, 0, sizeof (buf));           sAccept = INVALID_SOCKET;           sListen = INVALID_SOCKET;           wsaBuf.buf = buf;           wsaBuf.len = MAX_BUFFER;           opType =  OP_NULL;       }   public :       WSAOVERLAPPED ol;       SOCKET sAccept; // Only valid with AcceptEx        SOCKET sListen; // Only valid with AcceptEx        WSABUF wsaBuf;       char  buf[MAX_BUFFER];       OPERATIONINFO opType;   }PERIODATA, *PPERIODATA;      HANDLE  hThread[MAX_THREAD] = {0};   PERIODATA* pAcceptData[MAX_ACCEPT] = {0};   int  g_nThread = 0;   BOOL  g_bExitThread = FALSE;   LPFN_ACCEPTEX lpfnAcceptEx = NULL;   LPFN_GETACCEPTEXSOCKADDRS lpfnGetAcceptExSockAddrs = NULL;   GUID GuidAcceptEx = WSAID_ACCEPTEX;   GUID GuidGetAcceptExSockAddrs = WSAID_GETACCEPTEXSOCKADDRS;      unsigned __stdcall ThreadProc(LPVOID  lParam);   BOOL  PostAccept(PERIODATA* pIoData);      int  _tmain( int  argc, _TCHAR* argv[])   {       WORD  wVersionRequested = MAKEWORD(2, 2);       WSADATA wsaData;       if (0 != WSAStartup(wVersionRequested, &wsaData))       {           printf("WSAStartup failed with error code: %d/n" , GetLastError());           return  EXIT_FAILURE;       }          if (2 != HIBYTE(wsaData.wVersion) || 2 != LOBYTE(wsaData.wVersion))       {           printf("Socket version not supported./n" );           WSACleanup();           return  EXIT_FAILURE;       }          // Create IOCP        HANDLE  hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);       if (NULL == hIOCP)       {           printf("CreateIoCompletionPort failed with error code: %d/n" , WSAGetLastError());           WSACleanup();           return  EXIT_FAILURE;       }          // Create worker thread        SYSTEM_INFO si = {0};       GetSystemInfo(&si);       for ( int  i = 0; i < ( int )si.dwNumberOfProcessors+2; i++)       {           hThread[g_nThread] = (HANDLE )_beginthreadex(NULL, 0, ThreadProc, ( LPVOID )hIOCP, 0, NULL);           if (NULL == hThread[g_nThread])           {               printf("_beginthreadex failed with error code: %d/n" , GetLastError());               continue ;           }           ++g_nThread;              if (g_nThread > MAX_THREAD)           {               break ;           }       }          // Create listen SOCKET        SOCKET sListen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);       if (INVALID_SOCKET == sListen)       {           printf("WSASocket failed with error code: %d/n" , WSAGetLastError());           goto  EXIT_CODE;       }          // Associate SOCKET with IOCP        if (NULL == CreateIoCompletionPort(( HANDLE )sListen, hIOCP, NULL, 0))       {           printf("CreateIoCompletionPort failed with error code: %d/n" , WSAGetLastError());           if (INVALID_SOCKET != sListen)           {               closesocket(sListen);               sListen = INVALID_SOCKET;           }           goto  EXIT_CODE;       }          // Bind SOCKET        SOCKADDR_IN addr;       memset(&addr, 0, sizeof (addr));       addr.sin_family = AF_INET;       addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1" );       addr.sin_port = htons(5050);       if (SOCKET_ERROR == bind(sListen, (LPSOCKADDR)&addr,  sizeof (addr)))       {           printf("bind failed with error code: %d/n" , WSAGetLastError());           if (INVALID_SOCKET != sListen)           {               closesocket(sListen);               sListen = INVALID_SOCKET;           }           goto  EXIT_CODE;       }          // Start Listen        if (SOCKET_ERROR == listen(sListen, 200))       {           printf("listen failed with error code: %d/n" , WSAGetLastError());           if (INVALID_SOCKET != sListen)           {               closesocket(sListen);               sListen = INVALID_SOCKET;           }           goto  EXIT_CODE;       }          printf("Server start, wait for client to connect .../n" );          DWORD  dwBytes = 0;       if (SOCKET_ERROR == WSAIoctl(sListen, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx,  sizeof (GuidAcceptEx), &lpfnAcceptEx,           sizeof (lpfnAcceptEx), &dwBytes, NULL, NULL))       {           printf("WSAIoctl failed with error code: %d/n" , WSAGetLastError());           if (INVALID_SOCKET != sListen)           {               closesocket(sListen);               sListen = INVALID_SOCKET;           }           goto  EXIT_CODE;       }          if (SOCKET_ERROR == WSAIoctl(sListen, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidGetAcceptExSockAddrs,            sizeof (GuidGetAcceptExSockAddrs), &lpfnGetAcceptExSockAddrs,  sizeof (lpfnGetAcceptExSockAddrs),            &dwBytes, NULL, NULL))       {           printf("WSAIoctl failed with error code: %d/n" , WSAGetLastError());           if (INVALID_SOCKET != sListen)           {               closesocket(sListen);               sListen = INVALID_SOCKET;           }           goto  EXIT_CODE;       }          // Post MAX_ACCEPT accept        for ( int  i=0; i<MAX_ACCEPT; i++)       {           pAcceptData[i] = new  PERIODATA;           pAcceptData[i]->sListen = sListen;           PostAccept(pAcceptData[i]);       }       // After 1 hour later, Server shutdown.        Sleep(1000 * 60 *60);      EXIT_CODE:       g_bExitThread = TRUE;          PostQueuedCompletionStatus(hIOCP, 0, NULL, NULL);       WaitForMultipleObjects(g_nThread, hThread, TRUE, INFINITE);       for ( int  i = 0; i < g_nThread; i++)       {           CloseHandle(hThread[g_nThread]);       }          for ( int  i=0; i<MAX_ACCEPT; i++)       {           if (pAcceptData[i])           {               delete  pAcceptData[i];               pAcceptData[i] = NULL;           }       }          if (INVALID_SOCKET != sListen)       {           closesocket(sListen);           sListen = INVALID_SOCKET;       }       CloseHandle(hIOCP); // Close IOCP           WSACleanup();       return  0;   }      BOOL  PostAccept(PERIODATA* pIoData)   {       if (INVALID_SOCKET == pIoData->sListen)       {           return  FALSE;       }          DWORD  dwBytes = 0;       pIoData->opType = OP_ACCEPT;       pIoData->sAccept = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);       if (INVALID_SOCKET == pIoData->sAccept)       {           printf("WSASocket failed with error code: %d/n" , WSAGetLastError());           return  FALSE;       }          if (FALSE == lpfnAcceptEx(pIoData->sListen, pIoData->sAccept, pIoData->wsaBuf.buf, pIoData->wsaBuf.len - (( sizeof (SOCKADDR_IN)+16)*2),            sizeof (SOCKADDR_IN)+16,  sizeof (SOCKADDR_IN)+16, &dwBytes, &(pIoData->ol)))       {           if (WSA_IO_PENDING != WSAGetLastError())           {               printf("lpfnAcceptEx failed with error code: %d/n" , WSAGetLastError());                  return  FALSE;           }       }       return  TRUE;   }      unsigned __stdcall ThreadProc(LPVOID  lParam)   {       HANDLE  hIOCP = ( HANDLE )lParam;          PERHANDLEDATA* pPerHandleData = NULL;       PERIODATA* pPerIoData = NULL;       WSAOVERLAPPED* lpOverlapped = NULL;       DWORD  dwTrans = 0;       DWORD  dwFlags = 0;       while (!g_bExitThread)       {           BOOL  bRet = GetQueuedCompletionStatus(hIOCP, &dwTrans, ( PULONG_PTR )&pPerHandleData, &lpOverlapped, MAX_TIMEOUT);           if (!bRet)           {               // Timeout and exit thread                if (WAIT_TIMEOUT == GetLastError())               {                   continue ;               }               // Error                printf("GetQueuedCompletionStatus failed with error: %d/n" , GetLastError());               continue ;           }           else            {               pPerIoData = CONTAINING_RECORD(lpOverlapped, PERIODATA, ol);               if (NULL == pPerIoData)               {                   // Exit thread                    break ;               }                  if ((0 == dwTrans) && (OP_READ == pPerIoData->opType || OP_WRITE == pPerIoData->opType))               {                   // Client leave.                    printf("Client: <%s : %d> leave./n" , inet_ntoa(pPerHandleData->addr.sin_addr), ntohs(pPerHandleData->addr.sin_port));                   closesocket(pPerHandleData->sock);                   delete  pPerHandleData;                   delete  pPerIoData;                   continue ;               }               else                {                   switch (pPerIoData->opType)                   {                   case  OP_ACCEPT:  // Accept                        {                              SOCKADDR_IN* remote = NULL;                           SOCKADDR_IN* local = NULL;                           int  remoteLen =  sizeof (SOCKADDR_IN);                           int  localLen =  sizeof (SOCKADDR_IN);                           lpfnGetAcceptExSockAddrs(pPerIoData->wsaBuf.buf, pPerIoData->wsaBuf.len - ((sizeof (SOCKADDR_IN)+16)*2),                               sizeof (SOCKADDR_IN)+16,  sizeof (SOCKADDR_IN)+16, (LPSOCKADDR*)&local, &localLen, (LPSOCKADDR*)&remote, &remoteLen);                           printf("Client <%s : %d> come in./n" , inet_ntoa(remote->sin_addr), ntohs(remote->sin_port));                           printf("Recv Data: <%s : %d> %s./n" , inet_ntoa(remote->sin_addr), ntohs(remote->sin_port), pPerIoData->wsaBuf.buf);                              if (NULL != pPerHandleData)                           {                               delete  pPerHandleData;                               pPerHandleData = NULL;                           }                           pPerHandleData = new  PERHANDLEDATA;                           pPerHandleData->sock = pPerIoData->sAccept;                              PERHANDLEDATA* pPerHandle = new  PERHANDLEDATA;                           pPerHandle->sock = pPerIoData->sAccept;                           PERIODATA* pPerIo = new  PERIODATA;                           pPerIo->opType = OP_WRITE;                           strcpy_s(pPerIo->buf, MAX_BUFFER, pPerIoData->buf);                           DWORD  dwTrans = strlen(pPerIo->buf);                           memcpy(&(pPerHandleData->addr), remote, sizeof (SOCKADDR_IN));                           // Associate with IOCP                            if (NULL == CreateIoCompletionPort(( HANDLE )(pPerHandleData->sock), hIOCP, ( ULONG_PTR )pPerHandleData, 0))                           {                               printf("CreateIoCompletionPort failed with error code: %d/n" , GetLastError());                               closesocket(pPerHandleData->sock);                               delete  pPerHandleData;                               continue ;                           }                              // Post Accept                            memset(&(pPerIoData->ol), 0, sizeof (pPerIoData->ol));                           PostAccept(pPerIoData);                              // Post Receive                                                 DWORD  dwFlags = 0;                           if (SOCKET_ERROR == WSASend(pPerHandle->sock, &(pPerIo->wsaBuf), 1,                                &dwTrans, dwFlags, &(pPerIo->ol), NULL))                           {                               if (WSA_IO_PENDING != WSAGetLastError())                               {                                   printf("WSASend failed with error code: %d/n" , WSAGetLastError());                                   closesocket(pPerHandle->sock);                                   delete  pPerHandle;                                   delete  pPerIo;                                   continue ;                               }                           }                       }                       break ;                      case  OP_READ:  // Read                        printf("recv client <%s : %d> data: %s/n" , inet_ntoa(pPerHandleData->addr.sin_addr), ntohs(pPerHandleData->addr.sin_port), pPerIoData->buf);                       pPerIoData->opType = OP_WRITE;                       memset(&(pPerIoData->ol), 0, sizeof (pPerIoData->ol));                       if (SOCKET_ERROR == WSASend(pPerHandleData->sock, &(pPerIoData->wsaBuf), 1, &dwTrans, dwFlags, &(pPerIoData->ol), NULL))                       {                           if (WSA_IO_PENDING != WSAGetLastError())                           {                               printf("WSASend failed with error code: %d./n" , WSAGetLastError());                               continue ;                           }                       }                       break ;                      case  OP_WRITE:  // Write                        {                           pPerIoData->opType = OP_READ;                           dwFlags = 0;                           memset(&(pPerIoData->ol), 0, sizeof (pPerIoData->ol));                           memset(pPerIoData->buf, 0, sizeof (pPerIoData->buf));                           pPerIoData->wsaBuf.buf = pPerIoData->buf;                           dwTrans = pPerIoData->wsaBuf.len = MAX_BUFFER;                           if (SOCKET_ERROR == WSARecv(pPerHandleData->sock, &(pPerIoData->wsaBuf), 1, &dwTrans, &dwFlags, &(pPerIoData->ol), NULL))                           {                               if (WSA_IO_PENDING != WSAGetLastError())                               {                                   printf("WSARecv failed with error code: %d./n" , WSAGetLastError());                                   continue ;                               }                           }                       }                       break ;                      default :                       break ;                   }               }           }       }       return  0;   } 

    最新回复(0)