WIN网络编程-IOCP与可伸缩网络程序

/
//IOCPDemo.cpp文件   调试通过

//I/O完成端口最初的设计是应用程序发出一些异步I/O请求,当这些请求完

//成时,设备驱动把这些工作排序到完成端口,在完成端口等待的线程池

//可以处理这些完成I/O。

//首先调用CreateCompletionPort创建一个完成端口对象。函数的两个功能如下:

//1、创建一个完成端口对象。

//2、将一个或者多个文件句柄(此处是套节字)关联到I/O完成端口对象。

//最初创建时,需要设置的参数是NUMBEROFCONCURRENTTHREADS,它定义了允

//许在完成端口上同时执行的线程的数量。为0表示允许线程数量与处理器数

//量一样多。

//CreateIoCompletionPort函数的NumberOfConcurrentThreads参数个线程允

//许运行,即使创建了比允许线程更多的工作线程,仍只有允许线程数进

//入线程池。但是有时候,确实需要创建更多的线程,因为某个

//线程调用了一个函数,进行了暂停状态,体眠后暂时不能为线程池所有。所以

//必须有新的工作线程来补充。

//有了足够的线程来处理完成端口上的I/O请求之后,就该为完成端口关联套

//节字句柄,向完成端口关联套节字句柄之后,便可以通过在套节字上投递重叠

//发送和接收请求处理I/O,在这些I/O操作完成时,I/O系统会向完成端口对

//象发送一个完成通知封包。应用程序使用GetQueuedCompletionStatus函数

//可以取得这些队列中的封包,返回后说明发生了如下事件之一:

//1、GetQueuedCompletionStatus调用失败,说明在此套节字上有错误发生。

//2、BytesTransferred为0说明套节字被对方关闭。

//3、I/O请求成功完成。通过per-I/O数据中的OperationType域查看哪个I/O

//请求完成了。

//在每个套节字句柄关闭,通过PostQueuedCompletionStatus向工作线程发

//送特定的完成封包终止完成端口上处理的I/O线程,

 


#include "../common/initsock.h"
#include <stdio.h>
#include <windows.h>

// 初始化Winsock库
CInitSock theSock;

#define BUFFER_SIZE 1024

typedef struct_PER_HANDLE_DATA  //per-handle数据
{
 SOCKETs;   //对应的套节字句柄
 sockaddr_in addr; // 客户方地址
} PER_HANDLE_DATA, *PPER_HANDLE_DATA;


typedef struct_PER_IO_DATA   //per-I/O数据
{
 OVERLAPPEDol;   //重叠结构
 char buf[BUFFER_SIZE]; //数据缓冲区
 intnOperationType;  // 操作类型
#define OP_READ   1
#define OP_WRITE  2
#define OP_ACCEPT 3
} PER_IO_DATA, *PPER_IO_DATA;


DWORD WINAPI ServerThread(LPVOID lpParam)
{
 // 得到完成端口对象句柄
 HANDLE hCompletion = (HANDLE)lpParam;

 DWORD dwTrans;
 PPER_HANDLE_DATA pPerHandle;
 PPER_IO_DATA pPerIO;
 while(TRUE)
 {
  //在关联到此完成端口的所有套节字上等待I/O完成
  BOOL bOK =::GetQueuedCompletionStatus(hCompletion,
   &dwTrans,(LPDWORD)&pPerHandle,(LPOVERLAPPED*)&pPerIO, WSA_INFINITE);
  if(!bOK)      //在此套节字上有错误发生
  {
   ::closesocket(pPerHandle->s);
   ::GlobalFree(pPerHandle);
   ::GlobalFree(pPerIO);
   continue;
  }
  
  if(dwTrans == 0&&    //套节字被对方关闭
   (pPerIO->nOperationType== OP_READ || pPerIO->nOperationType ==OP_WRITE)) 
   
  {
   ::closesocket(pPerHandle->s);
   ::GlobalFree(pPerHandle);
   ::GlobalFree(pPerIO);
   continue;
  }

  switch(pPerIO->nOperationType) //通过per-I/O数据中的nOperationType域查看什么I/O请求完成了
  {
  caseOP_READ: // 完成一个接收请求
   {
    pPerIO->buf[dwTrans]= '/0';
    printf(pPerIO-> buf);
    
    //继续投递接收I/O请求
    WSABUFbuf;
    buf.buf= pPerIO->buf ;
    buf.len= BUFFER_SIZE;
    pPerIO->nOperationType= OP_READ;

    DWORDnFlags = 0;
    ::WSARecv(pPerHandle->s,&buf, 1, &dwTrans,&nFlags,&pPerIO->ol, NULL);
   }
   break;
  case OP_WRITE: //本例中没有投递这些类型的I/O请求
  case OP_ACCEPT:
   break;
  }
 }
 return 0;
}


void main()
{
 int nPort = 4567;
 //创建完成端口对象,创建工作线程处理完成端口对象中事件

//参数说明:

//

//HANDLE WINAPI CreateIoCompletionPort(//  __in      HANDLE FileHandle,要关联的套节字句柄//  __in_opt  HANDLE ExistingCompletionPort,
//上面创建的完成端口对象句柄// __in ULONG_PTR CompletionKey,
//一个句柄惟一数据,它将与FILEHANDLE套节字句柄关联在一起。
//可在此存储任意类型的信息。// __in DWORD NumberOfConcurrentThreads//);
 


 HANDLE hCompletion =::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);

//在此只创建了一个完成端口对象
 ::CreateThread(NULL, 0, ServerThread,(LPVOID)hCompletion, 0, 0);

 // 创建监听套节字,绑定到本地地址,开始监听
 SOCKET sListen = ::socket(AF_INET, SOCK_STREAM,0);
 SOCKADDR_IN si;
 si.sin_family = AF_INET;
 si.sin_port = ::ntohs(nPort);
 si.sin_addr.S_un.S_addr = INADDR_ANY;
 ::bind(sListen, (sockaddr*)&si,sizeof(si));
 ::listen(sListen, 5);

 // 循环处理到来的连接
 while(TRUE)
 {
  // 等待接受未决的连接请求
  SOCKADDR_IN saRemote;
  int nRemoteLen =sizeof(saRemote);

//创建新的接收套节字
  SOCKET sNew = ::accept(sListen,(sockaddr*)&saRemote,&nRemoteLen);

  //接受到新连接之后,为它创建一个per-handle数据,并将它们关联到完成端口对象。
  PPER_HANDLE_DATA pPerHandle=
       (PPER_HANDLE_DATA)::GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA));
  pPerHandle->s =sNew;
  memcpy(&pPerHandle->addr,&saRemote, nRemoteLen);

//多个套节字对应一个I/O完成对象
  ::CreateIoCompletionPort((HANDLE)pPerHandle->s,hCompletion, (DWORD)pPerHandle, 0);
 
  // 投递一个接收请求
  PPER_IO_DATA pPerIO =(PPER_IO_DATA)::GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
  pPerIO->nOperationType= OP_READ;
  WSABUF buf;
  buf.buf =pPerIO->buf;
  buf.len =BUFFER_SIZE; 
  DWORD dwRecv;
  DWORD dwFlags = 0;
  ::WSARecv(pPerHandle->s,&buf, 1, &dwRecv,&dwFlags,&pPerIO->ol, NULL);
 }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值