WINDOWS重叠IO模型

一. 重叠IO模型简介

重叠IO的核心实际上就是一个重叠的数据结构。应用程序在单个套接字上投递一个或者多个IO操作,当IO操作完成时对应的重叠数据结构中的事件对象会受信,相应的应用程序通过查事件对象可以得到通知。就这样,通过重叠的数据结构将异步的IO和程序连接起来了。

   重叠数据结构:

 

typedef struct _OVERLAPPED{

      DWORD Internal;

      DWORD InternalHigh;

      DWORD Offset;

      DWORD OffsetHigh;

      HANDLE hEvent//核心的参数,这个就是连接异步IO和应用程序的桥梁

}OVERLAPPED, *LPOVERLAPPED;

二.重叠IO模型的优点

    1.可以运行在支持winsock2的所有windows平台上(IOCP只能运行在NT平台上)

    2.比起阻塞,select,WSAAsyncSelect以及WSAEventSelect等模型提供了更好的系统级性能。

    3.使用重叠模型的应用程序通知缓冲区收发系统直接使用数据,也就是说,如果应用程序投递了一个10KB大小的缓冲区来接收数据,且数据已经到达套接字,则该数据直接    被拷贝到投递的缓冲区。(这一点和以上四种模型是截然不同的)

三。重叠IO机制的基本步骤

     1.要使用重叠数据结构我们就要使用新的IO函数(也就是send,recv,sendto,recvfrom要被WSASend(),WSARecv(),WSASendto(),WSARecvfrom(),WSAAccept()代替)。

     2.将WINDOWS事件对象与重叠数据结构相关联

     3.使用1中说的函数在套接字上投递IO请求

     4.不断的查询与重叠数据结构关联在一起的事件对象

    5.获得IO结果,处理结果。

四。废话少说直接上代码

     注意:这里是一份单线程的代码,所以它做多同时支持64个socket连接,如需更多的连接请采用线程池。

 

 

[cpp]  view plain copy
  1. #include "initsock.h"  
  2. #include <Mswsock.h>  
  3. #include "stdio.h"  
  4. #include <windows.h>  
  5.   
  6.   
  7. CInitSock theSock;  //主要用来初始化socket库  
  8. #define BUFFER_SIZE 1024  
  9.   
  10.   
  11. //这里是与套接字相关的信息  
  12. typedef struct _SOCKET_OBJ  
  13. {  
  14.     SOCKET s;  
  15.     int nOutstandingOps;  //此套接字上重叠IO的数量  
  16.     LPFN_ACCEPTEX lpfnAcceptEx;  //AcceptEx()函数的指针(仅对于监听套接字而言)  
  17. }SOCKET_OBJ,*PSOCKET_OBJ;  
  18.   
  19. typedef struct _BUFFER_OBJ  
  20. {  
  21.     OVERLAPPED ol;  //重叠的数据结构  
  22.     char* buff;   //投递IO请求时使用的缓冲区结构  
  23.     int nLen;    //缓冲区结构的长度  
  24.   
  25.     PSOCKET_OBJ   pSocket;  //SOCKET结构  
  26.     int nOperation;  //提交的操作类型  
  27. #define OP_ACCEPT  1  
  28. #define OP_READ    2  
  29. #define OP_WRITE   3  
  30.     SOCKET   sAccept;   //客户端套接字,仅对于监听套接字而言  
  31.     _BUFFER_OBJ *pNext;  
  32.   
  33. }BUFFER_OBJ,*PBUFFER_OBJ;  
  34.   
  35. HANDLE g_events[WSA_MAXIMUM_WAIT_EVENTS];  
  36. int g_nBufferCount;  
  37. PBUFFER_OBJ g_pBufferHead,g_pBufferTail;  
  38.   
  39. //申请套接字结构  
  40. PSOCKET_OBJ GetSocketObj(SOCKET s)  
  41. {  
  42.     PSOCKET_OBJ pSocket=(PSOCKET_OBJ)::GlobalAlloc(GPTR,sizeof(SOCKET_OBJ));  
  43.     if(pSocket!=NULL)  
  44.         pSocket->s=s;  
  45.     return pSocket;  
  46. }  
  47. void FreeSocketObj(PSOCKET_OBJ pSocket)  
  48. {  
  49.     if(pSocket->s!=INVALID_SOCKET)  
  50.         ::closesocket(pSocket->s);  
  51.     ::GlobalFree(pSocket);  
  52. }  
  53.   
  54. PBUFFER_OBJ GetBufferObj(PSOCKET_OBJ pSocket,ULONG nLen)  
  55. {  
  56.     if(g_nBufferCount>WSA_MAXIMUM_WAIT_EVENTS-1)  
  57.         return NULL;  
  58.     PBUFFER_OBJ pBuffer=(PBUFFER_OBJ)::GlobalAlloc(GPTR,sizeof(BUFFER_OBJ));  
  59.     if(pBuffer!=NULL)  
  60.     {  
  61.         pBuffer->buff=(char*)::GlobalAlloc(GPTR,nLen);  
  62.         pBuffer->ol.hEvent=WSACreateEvent();  
  63.         pBuffer->pSocket=pSocket;  
  64.         pBuffer->sAccept=INVALID_SOCKET;  
  65.   
  66.         if(g_pBufferHead==NULL)  
  67.         {  
  68.             g_pBufferHead=g_pBufferTail=pBuffer;  
  69.         }  
  70.         else  
  71.         {  
  72.             g_pBufferTail->pNext=pBuffer;  
  73.             g_pBufferTail=pBuffer;  
  74.         }  
  75.         g_events[++g_nBufferCount]=pBuffer->ol.hEvent;  
  76.     }  
  77.     return pBuffer;  
  78. }  
  79.   
  80. void FreeBufferObj(PBUFFER_OBJ pBuffer)  
  81. {  
  82.     PBUFFER_OBJ pTest=g_pBufferHead;  
  83.     BOOL bFind=FALSE;  
  84.     if(pTest==pBuffer)  //这边难道不会造成内存泄露吗?  
  85.     {  
  86.         g_pBufferHead=g_pBufferTail=NULL;  
  87.         bFind=TRUE;  
  88.     }  
  89.     else  
  90.     {  
  91.         while(pTest!=NULL&&pTest->pNext!=pBuffer)  
  92.         {  
  93.             pTest=pTest->pNext;  
  94.         }  
  95.         if(pTest!=NULL)  
  96.         {  
  97.             pTest->pNext=pBuffer->pNext;  
  98.             if(pTest->pNext==NULL)  
  99.                 g_pBufferTail=pTest;  
  100.             bFind=TRUE;  
  101.         }  
  102.     }  
  103.     if(bFind)  
  104.     {  
  105.         g_nBufferCount--;  
  106.         ::CloseHandle(pBuffer->ol.hEvent);  
  107.         ::GlobalFree(pBuffer->buff);  
  108.         ::GlobalFree(pBuffer);  
  109.     }  
  110. }  
  111.   
  112. void RebuildArray()  
  113. {  
  114.     PBUFFER_OBJ pBuffer = g_pBufferHead;  
  115.     int i =  1;  
  116.     while(pBuffer != NULL)  
  117.     {  
  118.         g_events[i++] = pBuffer->ol.hEvent;  
  119.         pBuffer = pBuffer->pNext;  
  120.     }  
  121. }  
  122. PBUFFER_OBJ FindBufferObj(HANDLE hEvent)  
  123. {  
  124.     PBUFFER_OBJ pBuffer=g_pBufferHead;  
  125.     while(pBuffer!=NULL)  
  126.     {  
  127.         if(pBuffer->ol.hEvent==hEvent)  
  128.             break;  
  129.         pBuffer=pBuffer->pNext;  
  130.     }  
  131.     return pBuffer;  
  132. }  
[cpp]  view plain copy
  1. /*  
[cpp]  view plain copy
  1. 后面有对AcceptEx这个函数进行说明  
[cpp]  view plain copy
  1. */  
  2. BOOL PostAccept(PBUFFER_OBJ pBuffer)  
  3. {  
  4.     PSOCKET_OBJ pSocket=pBuffer->pSocket;  
  5.     if(pSocket->lpfnAcceptEx!=NULL)  
  6.     {  
  7.         pBuffer->nOperation=OP_ACCEPT;  
  8.         pSocket->nOutstandingOps++;  
  9.   
  10.         //投递此IO请求  
  11.         DWORD dwBytes;  
  12.         pBuffer->sAccept=::WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);  
[cpp]  view plain copy
  1.                 //<span style="color:#ff6666;">注意:AcceptEx()如果提供了第四个参数,则这个函数会一直等到得到第一块数据才会返回。  
  2. </span>     BOOL b=pSocket->lpfnAcceptEx(pSocket->s,pBuffer->sAccept,pBuffer->buff,BUFFER_SIZE-((sizeof(sockaddr_in)+16)*2),sizeof(sockaddr_in)+16,  
  3.             sizeof(sockaddr_in)+16,&dwBytes,&pBuffer->ol);  
  4.         if(!b)  
  5.         {  
  6.             if(::WSAGetLastError()!=WSA_IO_PENDING)  
  7.                 return false;  
  8.         }  
  9.         return true;  
  10.     }  
  11.     return false;  
  12. }  
  13. BOOL PostRecv(PBUFFER_OBJ pBuffer)  
  14. {  
  15.     pBuffer->nOperation=OP_READ;  
  16.     pBuffer->pSocket->nOutstandingOps++;  
  17.   
  18.     DWORD dwBytes;  
  19.     DWORD dwFlags=0;  
  20.     WSABUF buf;  
  21.     buf.buf=pBuffer->buff;  
  22.     buf.len=pBuffer->nLen;  
  23.     if(::WSARecv(pBuffer->pSocket->s,&buf,1,&dwBytes,&dwFlags,&pBuffer->ol,NULL)!=NO_ERROR)  
  24.     {  
  25.         if(::WSAGetLastError()!=WSA_IO_PENDING)  
  26.             return false;  
  27.     }  
  28.     return true;  
  29. }  
  30. BOOL PostSend(PBUFFER_OBJ pBuffer)  
  31. {  
  32.     pBuffer->nOperation=OP_WRITE;  
  33.     pBuffer->pSocket->nOutstandingOps++;  
  34.   
  35.     DWORD dwBytes;  
  36.     DWORD dwFlags=0;  
  37.     WSABUF buf;  
  38.     buf.buf=pBuffer->buff;  
  39.     buf.len=pBuffer->nLen;  
  40.     if(::WSASend(pBuffer->pSocket->s,&buf,1,&dwBytes,dwFlags,&pBuffer->ol,NULL)!=NO_ERROR)  
  41.     {  
  42.         if(::WSAGetLastError()!=WSA_IO_PENDING)  
  43.             return false;  
  44.     }  
  45.     return true;  
  46. }  
  47.   
  48. //最重要的函数:IO处理函数  
  49.   
  50. BOOL HandleIO(PBUFFER_OBJ pBuffer)  
  51. {  
  52.     PSOCKET_OBJ pSocket=pBuffer->pSocket;  
  53.     pSocket->nOutstandingOps--;  
  54.   
  55.   
  56.     DWORD dwTrans;  
  57.     DWORD dwFlags;  
  58.     BOOL Ret=::WSAGetOverlappedResult(pBuffer->pSocket->s,&pBuffer->ol,&dwTrans,FALSE,&dwFlags);  
  59.     if(!Ret)  
  60.     {  
  61.         if(pSocket->s!=INVALID_SOCKET)  
  62.         {  
  63.             ::closesocket(pSocket->s);  
  64.             pSocket->s=INVALID_SOCKET;  
  65.         }  
  66.         if(pSocket->nOutstandingOps==0)  
  67.             FreeSocketObj(pSocket);  
  68.         FreeBufferObj(pBuffer);  
  69.         return FALSE;  
  70.     }  
  71.   
  72.     switch(pBuffer->nOperation)  
  73.     {  
  74.     case OP_ACCEPT:  
  75.         {  
  76.             PSOCKET_OBJ pClient=GetSocketObj(pBuffer->sAccept);  
  77.             PBUFFER_OBJ pSend=GetBufferObj(pClient,BUFFER_SIZE);  
  78.             if(pSend==NULL)  
  79.             {  
  80.                 printf("Too much  connections!");  
  81.                 FreeSocketObj(pClient);  
  82.                 return FALSE;  
  83.             }  
  84.             RebuildArray();  
  85.             pSend->nLen=dwTrans;  
  86.             memcpy(pSend->buff,pBuffer->buff,dwTrans);  
  87.   
  88.   
  89.             if(!PostSend(pSend))  
  90.             {  
  91.                 FreeSocketObj(pClient);  
  92.                 FreeBufferObj(pSend);  
  93.                 return FALSE;  
  94.             }  
  95.             PostAccept(pBuffer);  
  96.         }  
  97.         break;  
  98.     case OP_READ:  
  99.         if(dwTrans>0)  
  100.         {  
  101.             PBUFFER_OBJ pSend=pBuffer;  
  102.             pBuffer->nLen=dwTrans;  
  103.             PostSend(pSend);  
  104.         }  
  105.         else  
  106.         {  
  107.             if(pSocket->s!=INVALID_SOCKET)  
  108.             {  
  109.                 ::closesocket(pSocket->s);  
  110.                 pSocket->s=INVALID_SOCKET;  
  111.             }  
  112.             if(pSocket->nOutstandingOps==0)  
  113.                 FreeSocketObj(pSocket);  
  114.             FreeBufferObj(pBuffer);  
  115.             return FALSE;  
  116.         }  
  117.         break;  
  118.     case OP_WRITE:  
  119.         if(dwTrans>0)  
  120.         {  
  121.             pBuffer->nLen=BUFFER_SIZE;  
  122.             PostRecv(pBuffer);  
  123.         }  
  124.         else  
  125.         {  
  126.             if(pSocket->s!=INVALID_SOCKET)  
  127.             {  
  128.                 ::closesocket(pSocket->s);  
  129.                 pSocket->s=INVALID_SOCKET;  
  130.             }  
  131.             if(pSocket->nOutstandingOps==0)  
  132.                 FreeSocketObj(pSocket);  
  133.             FreeBufferObj(pBuffer);  
  134.             return FALSE;  
  135.         }  
  136.         break;  
  137.   
  138.     }  
  139.     return TRUE;  
  140. }  
  141. void main()  
  142. {  
  143.     // 创建监听套节字,绑定到本地端口,进入监听模式  
  144.     int nPort = 4567;  
  145.     SOCKET sListen =   
  146.         ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);  
  147.     SOCKADDR_IN si;  
  148.     si.sin_family = AF_INET;  
  149.     si.sin_port = ::ntohs(nPort);  
  150.     si.sin_addr.S_un.S_addr = INADDR_ANY;  
  151.     ::bind(sListen, (sockaddr*)&si, sizeof(si));  
  152.     ::listen(sListen, 200);  
  153.   
  154.     // 为监听套节字创建一个SOCKET_OBJ对象  
  155.     PSOCKET_OBJ pListen = GetSocketObj(sListen);  
  156.   
  157.     // 加载扩展函数AcceptEx  
  158.     GUID GuidAcceptEx = WSAID_ACCEPTEX;  
  159.     DWORD dwBytes;  
  160.     WSAIoctl(pListen->s,   
  161.         SIO_GET_EXTENSION_FUNCTION_POINTER,   
  162.         &GuidAcceptEx,   
  163.         sizeof(GuidAcceptEx),  
  164.         &pListen->lpfnAcceptEx,   
  165.         sizeof(pListen->lpfnAcceptEx),   
  166.         &dwBytes,   
  167.         NULL,   
  168.         NULL);  
  169.   
  170.     // 创建用来重新建立g_events数组的事件对象  
  171.     g_events[0] = ::WSACreateEvent();  
  172.   
  173.     // 在此可以投递多个接受I/O请求  
  174.     for(int i=0; i<5; i++)  
  175.     {  
  176.         PostAccept(GetBufferObj(pListen, BUFFER_SIZE));  
  177.     }  
  178.     ::WSASetEvent(g_events[0]);  
  179.       
  180.     while(TRUE)  
  181.     {  
  182.         int nIndex =   
  183.             ::WSAWaitForMultipleEvents(g_nBufferCount + 1, g_events, FALSE, WSA_INFINITE, FALSE);  
  184.         if(nIndex == WSA_WAIT_FAILED)  
  185.         {  
  186.             printf("WSAWaitForMultipleEvents() failed \n");  
  187.             break;  
  188.         }  
  189.         nIndex = nIndex - WSA_WAIT_EVENT_0;  
  190.         for(int i=0; i<=nIndex; i++)  
  191.         {  
  192.             int nRet = ::WSAWaitForMultipleEvents(1, &g_events[i], TRUE, 0, FALSE);  
  193.             if(nRet == WSA_WAIT_TIMEOUT)  
  194.                 continue;  
  195.             else  
  196.             {  
  197.                 ::WSAResetEvent(g_events[i]);  
  198.                 // 重新建立g_events数组  
  199.                 if(i == 0)  
  200.                 {  
  201.                     RebuildArray();  
  202.                     continue;  
  203.                 }  
  204.   
  205.                 // 处理这个I/O  
  206.                 PBUFFER_OBJ pBuffer = FindBufferObj(g_events[i]);  
  207.                 if(pBuffer != NULL)  
  208.                 {  
  209.                     if(!HandleIO(pBuffer))  
  210.                         RebuildArray();  
  211.                 }  
  212.             }  
  213.         }  
  214.     }  
  215. }  

 

   

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值