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;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值