博客首页 注册 建议与交流 排行榜 加入友情链接
推荐 投诉 搜索: 帮助

计算机资料&彩票

努力学习 推荐
wrtrtew.cublog.cn


IOCP机制的简单服务器程序
// CMyIOCPServer.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"

//目标,使用IOCP机制做一个聊天的服务器,这个服务器记录连接的用户,并转发客户端自己的消息,相当于一个群聊天工具
 
#define PACKET_LEN 2048
struct PER_IO_CONTEXT
{
 SOCKET hSocket;
 in_addr RemoteAddr;
 int nPort;
 PER_IO_CONTEXT *pNext;
};
typedef struct _PER_IO_DATA
{
 OVERLAPPED  ol;
 int len;
 char buf[PACKET_LEN];
 int nOperateType;
#define OP_READ 1
#define OP_WRITE 2
}PER_IO_DATA;
DWORD WINAPI ServerThread(LPVOID lParam);
BOOL PostRecv(PER_IO_CONTEXT *pPerIoContext,PER_IO_DATA *pPerIoData);
BOOL PostSend(PER_IO_CONTEXT *pPerIoContext,PER_IO_DATA *pPerIoData);
//记录一个全局的列表,用来向全部连接的客户进行消息转发
PER_IO_CONTEXT *g_pPerIoContext; 
int g_nClient;
void AddIoContext(PER_IO_CONTEXT *pPerIoContext);
void GetIoContext(PER_IO_CONTEXT *pPerIoContext);
void RemoveIoContext(PER_IO_CONTEXT *pPerIoContext);
void SendToOther(PER_IO_CONTEXT *pSelfContext,PER_IO_DATA *pPerIoData);
void ReleaseData(PER_IO_DATA *pIoData);
int _tmain(int argc, _TCHAR* argv[])
{
 WSADATA wsaData;
 WSAStartup(MAKEWORD(2,2),&wsaData);
 g_pPerIoContext=NULL;
 g_nClient=0;
 SOCKET hListen=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
 HANDLE hCompletion=::CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);
 CreateThread(NULL,0,ServerThread,(LPVOID)hCompletion,0,0);
 SOCKADDR_IN sin;
 sin.sin_addr.S_un.S_addr=ADDR_ANY;
 sin.sin_family=AF_INET;
 sin.sin_port=htons(3456);
 if(::bind(hListen,(sockaddr*)&sin,sizeof(sin))==SOCKET_ERROR)
 {
  printf("bind error.\n");
  goto LINEERROR;
 } 
 if(::listen(hListen,10)==SOCKET_ERROR)
 {
  printf("listen error.\n");
  goto LINEERROR;
 }
 printf("服务器开始监听....... \n");
 SOCKADDR_IN acceptAddr;
 int acceptLen=sizeof(SOCKADDR_IN);
 SOCKET hClient;
 
 while(true)
 {
  hClient=::accept(hListen,(sockaddr*)&acceptAddr,&acceptLen);
  PER_IO_CONTEXT *pIoContext=(PER_IO_CONTEXT*)GlobalAlloc(GPTR,sizeof(PER_IO_CONTEXT));
  pIoContext->hSocket=hClient;
  pIoContext->RemoteAddr=acceptAddr.sin_addr;
  pIoContext->nPort=ntohs(acceptAddr.sin_port);
  AddIoContext(pIoContext);
  g_nClient++;
  printf("一个客户到来了 IP:PORT %s:%d  (%d) \n",inet_ntoa(acceptAddr.sin_addr),pIoContext->nPort,g_nClient);
  ::CreateIoCompletionPort((HANDLE)pIoContext->hSocket,hCompletion,(DWORD)pIoContext,0);

  //投递一个请求
  PER_IO_DATA *pIoData=(PER_IO_DATA*)GlobalAlloc(GPTR,sizeof(PER_IO_DATA));
  pIoData->len=PACKET_LEN;
  
  PostRecv(pIoContext,pIoData);
 }
 
LINEERROR:
 WSACleanup();
 return 0;
}
DWORD WINAPI ServerThread(LPVOID lParam)
{
 HANDLE hCompletionPort=(HANDLE)lParam;
 DWORD dwTransferBytes=0;
 PER_IO_CONTEXT *pIoContext;
 PER_IO_DATA *pIoData;
 while(TRUE)
 {
  BOOL bOK=GetQueuedCompletionStatus(hCompletionPort,&dwTransferBytes,(LPDWORD)&pIoContext,(LPOVERLAPPED*)&pIoData,WSA_INFINITE);
  if(!bOK)
  {
   int nError=GetLastError();
   printf("GetQueuedCompletionStatus Error! %d \n",nError);
   g_nClient--;
   printf("一个客户发生了错误 IP:PORT %s:%d  (%d) \n",inet_ntoa(pIoContext->RemoteAddr),pIoContext->nPort,g_nClient); 
   RemoveIoContext(pIoContext);
   continue;
  }
        else if(dwTransferBytes==0)
  {
   
   g_nClient--;
   printf("一个客户断开了 IP:PORT %s:%d  (%d) \n",inet_ntoa(pIoContext->RemoteAddr),pIoContext->nPort,g_nClient); 
   RemoveIoContext(pIoContext);
  }
  else
  {
   if(pIoData->nOperateType==OP_READ)
   {
    //转发消息
    SendToOther(pIoContext,pIoData);
    //投递一个请求
          PER_IO_DATA *p2IoData=(PER_IO_DATA*)GlobalAlloc(GPTR,sizeof(PER_IO_DATA));
    p2IoData->len=PACKET_LEN;
  
          PostRecv(pIoContext,p2IoData);
    
   }
   else if(pIoData->nOperateType==OP_WRITE)  //写操作完成了
   {
    ReleaseData(pIoData);
   }
  }
 }
}
void AddIoContext(PER_IO_CONTEXT *pPerIoContext)
{
 //维护一个链表
 pPerIoContext->pNext=g_pPerIoContext;
 g_pPerIoContext=pPerIoContext;
}
void GetIoContext(PER_IO_CONTEXT *pPerIoContext)
{
}
void RemoveIoContext(PER_IO_CONTEXT *pPerIoContext)
{
 if(g_pPerIoContext==NULL)
  return;
 else if(g_pPerIoContext->hSocket==pPerIoContext->hSocket)
 {
  g_pPerIoContext=g_pPerIoContext->pNext;
 }
 else
 {
  PER_IO_CONTEXT *pIoContext=g_pPerIoContext;
  PER_IO_CONTEXT *pNextIoContext=pIoContext->pNext;
  while(pNextIoContext)
  {
   if(pNextIoContext->hSocket==pPerIoContext->hSocket)
   {
    pIoContext->pNext=pNextIoContext->pNext;
    break;
   }
   pIoContext=pNextIoContext;
   pNextIoContext=pNextIoContext->pNext;
  }
 }
 ::closesocket(pPerIoContext->hSocket);
 GlobalFree((HGLOBAL)pPerIoContext);
}
void SendToOther(PER_IO_CONTEXT *pSelfContext,PER_IO_DATA *pPerIoData)
{
 if(g_pPerIoContext==NULL)
  return;
 else
 {
  PER_IO_CONTEXT *pIoContext=g_pPerIoContext;
  while(pIoContext)
  {
   if(pSelfContext->hSocket!=pIoContext->hSocket)
   {
    PostSend(pIoContext,pPerIoData);
    //::send(pIoContext->hSocket,pPerIoData->buf,pPerIoData->len,0);
   }
   pIoContext=pIoContext->pNext;
  }
 }
}
void ReleaseData(PER_IO_DATA *pIoData)
{
 ::GlobalFree((HGLOBAL)pIoData);
}
BOOL PostRecv(PER_IO_CONTEXT *pPerIoContext,PER_IO_DATA *pPerIoData)
{
 pPerIoData->nOperateType=OP_READ;
 WSABUF buf;
 buf.buf=pPerIoData->buf;
 buf.len=pPerIoData->len;
 DWORD dwRecvBytes=0;
 DWORD dwFlags=0;
 if(WSARecv(pPerIoContext->hSocket,&buf,1,&dwRecvBytes,&dwFlags,&pPerIoData->ol,NULL)!=NO_ERROR)
 {
  if(WSAGetLastError()==WSA_IO_PENDING)
   return TRUE;
  return FALSE;
 }
 return TRUE;
}
BOOL PostSend(PER_IO_CONTEXT *pPerIoContext,PER_IO_DATA *pPerIoData)
{
 pPerIoData->nOperateType=OP_WRITE;
 WSABUF buf;
 buf.buf=pPerIoData->buf;
 buf.len=pPerIoData->len;
 DWORD dwSendBytes=0;
 DWORD dwFlags=0;
 if(WSASend(pPerIoContext->hSocket,&buf,1,&dwSendBytes,dwFlags,&pPerIoData->ol,NULL)!=NO_ERROR)
 {
  if(WSAGetLastError()==WSA_IO_PENDING)
   return TRUE;
  return FALSE;
 }
 return TRUE;
}

 

发表于: 2008-04-01 ,修改于: 2008-04-01 22:02,已浏览163次,有评论0条 推荐 投诉


网友评论

发表评论