WinSock 重叠I/O 服务端模型

发布时间:2016-12-9 15:58:42 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"WinSock 重叠I/O 服务端模型",主要涉及到WinSock 重叠I/O 服务端模型方面的内容,对于WinSock 重叠I/O 服务端模型感兴趣的同学可以参考一下。

#include "stdafx.h"#include <WinSock2.h>#include <mswsock.h>#include <malloc.h>#pragma comment(lib,"Ws2_32.lib")#define BUFFER_SIZE 1024 void InitSock(){ WORD wVersionRequested; WSADATA wsaData; int err;   wVersionRequested = MAKEWORD( 2, 2 );   err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) {  /* Tell the user that we could not find a usable */  /* WinSock DLL.                                  */  return; }   /* Confirm that the WinSock DLL supports 2.2.*/ /* Note that if the DLL supports versions greater    */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we      */ /* requested.                                        */   if ( LOBYTE( wsaData.wVersion ) != 2 ||   HIBYTE( wsaData.wVersion ) != 2 ) {  /* Tell the user that we could not find a usable */  /* WinSock DLL.                                  */  WSACleanup( );  return;  }} //socket 对象typedef struct _SOCKET_OBJ{ SOCKET s;    //套接字句柄  int nOutstandingOpts;  //记录此套接字上的重叠I/O数量 LPFN_ACCEPTEX lpfnAcceptEx; //扩展函数AcceptEx的指针(仅对监听套接字而言)}SOCKET_OBJ,*pSOCKET_OBJ; //申请套接字对象pSOCKET_OBJ GetSocketObj(SOCKET s){ pSOCKET_OBJ pSocketObj=(pSOCKET_OBJ)malloc(sizeof(SOCKET_OBJ)); if(pSocketObj!=NULL) {  pSocketObj->s=s;  pSocketObj->nOutstandingOpts=0;  pSocketObj->lpfnAcceptEx=NULL; } return pSocketObj;} //释放套接字对象void FreeSocketObj(pSOCKET_OBJ pSocketObj){ if(INVALID_SOCKET!=pSocketObj->s) {  closesocket(pSocketObj->s); } free(pSocketObj); pSocketObj=NULL;} //缓冲区对象typedef struct _BUFFER_OBJ{ OVERLAPPED ol;   //重叠结构 char *buf;       //send,recv,accept 缓冲区地址  int nLen;        //buf的长度 pSOCKET_OBJ pSocket;  //套接字对象 int nOperation;   //操作类型#define OP_ACCEPT 1#define OP_READ 2#define OP_WRITE 3 SOCKET sAccept;   //用来保存acceptex接受的客户套接字(仅对监听套接字而言) _BUFFER_OBJ *pNext;   //指向下一个缓冲区对象}BUFFER_OBJ,*pBUFFER_OBJ; WSAEVENT events[WSA_MAXIMUM_WAIT_EVENTS];  //I/O事件句柄数组int g_nBufCount=0;    // 数组中有句柄数量pBUFFER_OBJ g_pBufferHead,g_pBufferTail; //缓冲区列表头和尾指针 //申请一个缓冲区对象pBUFFER_OBJ GetBufferObj(pSOCKET_OBJ pSocket){ if(g_nBufCount>WSA_MAXIMUM_WAIT_EVENTS-1) {  printf("too many connections/n");  return NULL; } pBUFFER_OBJ pBuffer=(pBUFFER_OBJ)malloc(sizeof(BUFFER_OBJ)); if(pBuffer!=NULL) {  pBuffer->buf=(char *)malloc(BUFFER_SIZE);  pBuffer->pSocket=pSocket;  pBuffer->ol.hEvent=WSACreateEvent();  pBuffer->pNext=NULL;  pBuffer->sAccept=INVALID_SOCKET;   //将pBuffer添加到缓冲区列表中  if(g_pBufferHead==NULL)  {   g_pBufferHead=g_pBufferTail=pBuffer;  }  else  {   g_pBufferTail->pNext=pBuffer;   g_pBufferTail=pBuffer;  }  events[++g_nBufCount]=pBuffer->ol.hEvent; } return pBuffer;} //释放缓冲区对象void FreeBufferObj(pBUFFER_OBJ pBuffer){ pBUFFER_OBJ pTemp=g_pBufferHead; BOOL bFind=false; if(pTemp==pBuffer) {  if(g_pBufferHead==g_pBufferTail)  {   g_pBufferHead=g_pBufferTail=NULL;  }  else  {   g_pBufferHead=pBuffer->pNext;  }  bFind=true; } else {  while(pTemp!=NULL&&pTemp->pNext!=pBuffer)  {   pTemp=pTemp->pNext;  }  if(pTemp!=NULL)  {   pTemp->pNext=pBuffer->pNext;   if(pTemp->pNext==NULL)    g_pBufferTail=pTemp;   bFind=true;  } } if(bFind) {  g_nBufCount--;  ::CloseHandle(pBuffer->ol.hEvent);  free(pBuffer->buf);  free(pBuffer); }} pBUFFER_OBJ FindBufferObj(WSAEVENT hEvent){ pBUFFER_OBJ pBuffer=g_pBufferHead; while(pBuffer!=NULL) {  if(pBuffer->ol.hEvent==hEvent)  {   break;  }  pBuffer=pBuffer->pNext; } return pBuffer;} void RebuildArray(){ pBUFFER_OBJ pBufferObj=g_pBufferHead; int i=1; while(pBufferObj!=NULL) {  events[i++]=pBufferObj->ol.hEvent;  pBufferObj=pBufferObj->pNext; }}BOOL PostAccept(pBUFFER_OBJ pBuffer){ pSOCKET_OBJ pSocket=pBuffer->pSocket; if(pSocket->lpfnAcceptEx!=NULL) {  pBuffer->nOperation=OP_ACCEPT;  pSocket->nOutstandingOpts++;  DWORD dwBytes;  pBuffer->sAccept=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);  BOOL b=pSocket->lpfnAcceptEx(pSocket->s,pBuffer->sAccept,pBuffer->buf,BUFFER_SIZE-(sizeof(sockaddr)+16)*2,   sizeof(sockaddr)+16,sizeof(sockaddr)+16,&dwBytes,&pBuffer->ol);  if(!b)  {   if(WSA_IO_PENDING!=WSAGetLastError())   {    return false;   }  }  return true; } return false;} BOOL PostRecv(pBUFFER_OBJ pBuffer){ pSOCKET_OBJ pSocket=pBuffer->pSocket; pSocket->nOutstandingOpts++; pBuffer->nOperation=OP_READ; DWORD dwBytes; DWORD dwFlags=0; WSABUF buf; buf.buf=pBuffer->buf; buf.len=BUFFER_SIZE; if(SOCKET_ERROR!=WSARecv(pSocket->s,&buf,1,&dwBytes,&dwFlags,&pBuffer->ol,NULL)) {  if(WSA_IO_PENDING!=WSAGetLastError())  {   return false;  } } return true;} //BOOL PostSend(...){....} BOOL HandleIO(pBUFFER_OBJ pBuffer){ pSOCKET_OBJ pSocket=pBuffer->pSocket; pSocket->nOutstandingOpts--; DWORD dwTrans; DWORD dwFlags; BOOL bRet=::WSAGetOverlappedResult(pSocket->s,&pBuffer->ol,&dwTrans,false,&dwFlags); if(!bRet) {  if(pSocket->s!=INVALID_SOCKET)  {   closesocket(pSocket->s);   pSocket->s=INVALID_SOCKET;  }  if(pSocket->nOutstandingOpts==0)  {   FreeSocketObj(pSocket);  }  FreeBufferObj(pBuffer);  return false; } pSOCKET_OBJ pClient; pBUFFER_OBJ pRecv; switch(pBuffer->nOperation) { case OP_ACCEPT:  pClient=GetSocketObj(pBuffer->sAccept);  pRecv=GetBufferObj(pClient);  if(pRecv==NULL)  {   return false;  }  RebuildArray();  if(!PostRecv(pRecv))  {   ::FreeSocketObj(pClient);   ::FreeBufferObj(pRecv);   return false;  }  printf("一新连接/n");  pBuffer->buf[dwTrans]='/0';  printf("收到数据:%s/n",pBuffer->buf);  ::ZeroMemory(pBuffer->buf,BUFFER_SIZE);  PostAccept(pBuffer);  break; case OP_READ:  if(dwTrans>0)  {   pBuffer->buf[dwTrans]='/0';   printf("收到数据:%s/n",pBuffer->buf);   ::ZeroMemory(pBuffer->buf,BUFFER_SIZE);   if(!PostRecv(pBuffer))   {    printf("继开一连接/n");    ::closesocket(pSocket->s);    pSocket->s=INVALID_SOCKET;    ::FreeBufferObj(pRecv);    return false;   }  }  else  {   //必须关闭socket 以便   printf("继开一连接/n");       if(pSocket->s!=INVALID_SOCKET)   {    ::closesocket(pSocket->s);    pSocket->s=INVALID_SOCKET;   }   if(pSocket->nOutstandingOpts==0)   {    FreeSocketObj(pSocket);   }   ::FreeBufferObj(pBuffer);   return false;  }  break; } return true;}int _tmain(int argc, _TCHAR* argv[]){ InitSock(); SOCKET sListen=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED); sockaddr_in addr; addr.sin_addr.S_un.S_addr=INADDR_ANY; addr.sin_family=AF_INET; addr.sin_port=htons(1456); if(SOCKET_ERROR==bind(sListen,(sockaddr *)&addr,sizeof(sockaddr))) {  printf("绑定失败/n");  ::closesocket(sListen);  ::WSACleanup();  return 0; } listen(sListen,15); pSOCKET_OBJ pListen=GetSocketObj(sListen); GUID guid=WSAID_ACCEPTEX; DWORD dwBytes; ::WSAIoctl(pListen->s,SIO_GET_EXTENSION_FUNCTION_POINTER,&guid,sizeof(guid),&pListen->lpfnAcceptEx,sizeof(pListen->lpfnAcceptEx),  &dwBytes,NULL,NULL); events[0]=WSACreateEvent(); for(int i=0;i<5;i++) {  BOOL B=PostAccept(GetBufferObj(pListen)); } ::WSASetEvent(events[0]); while(true) {  int nIndex=::WSAWaitForMultipleEvents(g_nBufCount+1,events,false,WSA_INFINITE,false);  if(nIndex==WSA_WAIT_FAILED)  {   printf("wait failed/n");   break;  }  nIndex=nIndex-WSA_WAIT_EVENT_0;  for(int i=nIndex;i<g_nBufCount+1;i++)  {   int nRet=::WSAWaitForMultipleEvents(1,&events[i],true,0,false);   if(nRet==WSA_WAIT_TIMEOUT||nRet==WSA_WAIT_FAILED)   {    continue;   }   else   {    ::WSAResetEvent(events[i]);    if(i==0)    {     ::RebuildArray();     continue;    }    pBUFFER_OBJ pBuffer=::FindBufferObj(events[i]);    if(pBuffer!=NULL)    {     if(!HandleIO(pBuffer))     {      ::RebuildArray();     }    }   }  } } return 0;} 

上一篇:开“会”啦!
下一篇:在这里查查东西应该还是不错的

相关文章

相关评论