有关“完成端口”

原帖地址:http://topic.csdn.net/t/20041229/11/3684912.html

 

使用完成端口的一次实验。

楼主 ZHENG017() 2004-12-29 11:37:50 在 VC/MFC / 网络编程 提问

使用完成端口的单台服务器最多可连接2500个客户端  
  最近在做一个完成端口的项目,希望测试一下在普通Win2k   Pro下最多可容纳的客户端。众所诸知,当客户connect到server,CreateIoCompletionPort后调用WSARecv等待客 户端主动主报的数据。下面就是测试程序,单个客户端程序连接后,不停的调用wsarecv,观察非页面缓冲池的大小,发现到非页面缓冲池为800多K,而 循环次数为2500的时候,程序崩溃。  
  wsarecv调用时会将指定的页面锁定到物理内存中,该页面不会被交换出去。。。  
  我的2500次wsarecv锁定了800多K.  
  于是程序就飞了,还好,系统没有发疯。win2k还是比较稳定的。  
  再加上创建socket等操作也需要占用非页面缓冲池,估计实际的单台服务器所连接的客户端比2500还要少。  
  在单个socket同一个overlapped上,如果同时存在wsarecv和wsasend,喝喝,也就是说在wsarecv一直存在,在 wsasend末完成前wsarecv接收到了数据,如果在GetQueuedCompletionStatus时只好自己来决定是wsarecv还是 wsasend.这种情况真的很难办。我无法决定是wsarecv返回还是wsasend返回.于是在单个socket同一个overlapped上,一 次只能有一个wsarecv或wsasend,在调用wsasend之前,必须判断是否存在wsarecv,如有,调用cancelio取消,把占用的页 面换出来。当然也可以只调用wsarecv,在收到数据后具体的事务处理中使用send,recv等就没这么多烦恼了。  
  如果存在多个wsarecv在单个socket上,其所占用的页面会一定直锁定,直到在该wsarecv收到数据或调用cancleio,或PostQueuedCompletionStatus或进程终止。。。为止。  
  #include   <winsock2.h>  
  #include   <windows.h>  
  #include   <stdio.h>  
  #pragma   comment(lib,"ws2_32.lib")  
  #define   PORT   5150  
  #define   DATA_BUFSIZE   8192  
   
  typedef   struct  
  {  
        OVERLAPPED   Overlapped;  
        WSABUF   DataBuf;  
        CHAR   Buffer[DATA_BUFSIZE];  
        DWORD   BytesSEND;  
        DWORD   BytesRECV;  
  }   PER_IO_OPERATION_DATA,   *   LPPER_IO_OPERATION_DATA;  
   
   
  typedef   struct    
  {  
        SOCKET   Socket;  
  }   PER_HANDLE_DATA,   *   LPPER_HANDLE_DATA;  
   
   
  DWORD   __stdcall   ServerWorkerThread(LPVOID   CompletionPortID){return   0;};  
   
  void   main(void)  
  {  
        SOCKET   Listen,Accept;  
        HANDLE   CompletionPort;  
        LPPER_HANDLE_DATA   PerHandleData;  
        LPPER_IO_OPERATION_DATA   PerIoData;  
        DWORD   RecvBytes,   Flags;  
        WSADATA   wsaData;  
        if   ((   WSAStartup(0x0202,   &wsaData))   !=   0)  
        {  
              return;  
        }  
        if   ((CompletionPort   =   CreateIoCompletionPort(INVALID_HANDLE_VALUE,   NULL,   0,   0))   ==   NULL)  
        {  
              printf(   "CreateIoCompletionPort   failed   with   error:   %d/n",   GetLastError());  
              return;  
        }  
   
        if   ((Listen   =   WSASocket(AF_INET,   SOCK_STREAM,   0,   NULL,   0,   WSA_FLAG_OVERLAPPED))   ==   INVALID_SOCKET)  
        {  
              printf("WSASocket()   failed   with   error   %d/n",   WSAGetLastError());  
              return;  
        }    
        DWORD   MemorySize   =   256*1024*1024;  
        BOOL   Result   =   FALSE;  
        do   {  
          Result   =   SetProcessWorkingSetSize(GetCurrentProcess(),   MemorySize,     MemorySize*2);  
          if   (!Result)    
          {  
            MemorySize   -=   10*1024*1024;  
          }  
        }   while   (   !Result   );  
        printf("MemorySize   is   %dM/n",MemorySize/1024/1024);  
        struct   sockaddr_in   stddr={0};  
        int         iAddrLen   =   sizeof(struct   sockaddr_in);  
        stddr.sin_family   =   AF_INET;  
        stddr.sin_addr.s_addr   =   htonl(INADDR_ANY);  
        stddr.sin_port   =   htons(PORT);  
   
        if   (bind(Listen,   (PSOCKADDR)   &stddr,   sizeof(stddr))   ==   SOCKET_ERROR)  
        {  
              printf("bind()   failed   with   error   %d/n",   WSAGetLastError());  
              return;  
        }  
        if   (listen(Listen,   1)   ==   SOCKET_ERROR)  
        {  
              printf("listen()   failed   with   error   %d/n",   WSAGetLastError());  
              return;  
        }  
   
        while(TRUE)  
        {  
              if   ((Accept   =   WSAAccept(Listen,(sockaddr*)   &stddr,   &iAddrLen,   NULL,   0))   ==   SOCKET_ERROR)  
              {  
                    printf("WSAAccept()   failed   with   error   %d/n",   WSAGetLastError());  
                    return;  
              }  
 printf("%s/n",inet_ntoa(stddr.sin_addr));  
              if   ((PerHandleData   =   (LPPER_HANDLE_DATA)   GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA)))   ==   NULL)  
              {  
                    printf("GlobalAlloc()   failed   with   error   %d/n",   GetLastError());  
                    return;  
              }  
              printf("Socket   number   %d   connected/n",   Accept);  
              PerHandleData->Socket   =   Accept;  
   
              if   (CreateIoCompletionPort((HANDLE)   Accept,   CompletionPort,   (DWORD)   PerHandleData,0)   ==   NULL)  
              {  
                    printf("CreateIoCompletionPort   failed   with   error   %d/n",   GetLastError());  
                    return;  
              }  
              if   ((PerIoData   =   (LPPER_IO_OPERATION_DATA)   GlobalAlloc(GPTR,   sizeof(PER_IO_OPERATION_DATA)))   ==   NULL)  
              {  
                    printf("GlobalAlloc()   failed   with   error   %d/n",   GetLastError());  
                    return;  
              }  
   
              ZeroMemory(&(PerIoData->Overlapped),   sizeof(OVERLAPPED));  
              PerIoData->BytesSEND   =   0;  
              PerIoData->BytesRECV   =   0;  
              PerIoData->DataBuf.len   =   DATA_BUFSIZE;  
              PerIoData->DataBuf.buf   =   PerIoData->Buffer;  
   
        Flags   =   0;  
        int   iLoop   =   0;  
        char   chTemp[256]   =   {0};  
        while   (++   iLoop)  
        {  
          if   (WSARecv(Accept,   &(PerIoData->DataBuf),   1,   &RecvBytes,   &Flags,  
            &(PerIoData->Overlapped),   NULL)   ==   SOCKET_ERROR)  
          {  
            if   (WSAGetLastError()   !=   ERROR_IO_PENDING)  
            {  
              printf("WSARecv()   failed   with   error   %d/n",   WSAGetLastError());  
              return;  
            }  
          }  
   
          printf("WSARecv   循环次数为%d/n",iLoop);  
          sprintf(chTemp,"WSARecv   循环次数为%d/n",iLoop);  
          OutputDebugString(chTemp);  
          Sleep(10);  
        }  
        }  
  }  

 

2 楼 redchina(风清云淡) 回复于 2004-12-29 11:54:33 得分 10

http://www.codetools.com/internet/winsockiocp.asp  
  上边的网址提供了一个完成端口的比较好的例子,可以解决你的困惑,另外如果你的2500次wsarecv均处于待决状态,显然则属于典型的拒绝式服务攻击,这种你可以通过设定一个检测线程来解决这个问题。

 

http://www.codeproject.com/KB/IP/winsockiocp.aspx

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值