使用完成端口的单台服务器最多可连接2500个客户端

最近在做一个完成端口的项目,希望测试一下在普通Win2k Pro下最多可容纳的客户端。众所诸知,当客户connect到server,CreateIoCompletionPort后调用WSARecv等待客户端主动主报的数据。下面就是测试程序,单个客户端程序连接后,不停的调用wsarecv,观察非页面缓冲池的大小,发现到非页面缓冲池为800多K,而循环次数为2500的时候,程序崩溃。
wsarecv调用时会将指定的页面锁定到物理内存中,该页面不会被交换出去。。。
我的2500次wsarecv锁定了800多K.而且将DATA_BUFSIZE减少到8也没有任何改善情况。
于是程序就飞了,还好,系统没有发疯。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);
   }
   }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以通过以下步骤来在服务器使用Socket类创建服务器端,监听客户端连接请求: 1. 引用命名空间:在代码中引用System.Net.Sockets命名空间,以便使用Socket类。 2. 创建Socket对象:使用Socket类的构造函数创建一个Socket对象。 ``` Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ``` AddressFamily.InterNetwork指定使用IPv4协议,SocketType.Stream指定使用流式套接字,ProtocolType.Tcp指定使用TCP协议。 3. 绑定IP地址和端口号:使用Bind方法将Socket对象绑定到指定的IP地址和端口号上。 ``` IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888); listener.Bind(localEndPoint); ``` 这里使用了IP地址127.0.0.1和端口号8888。 4. 开始监听连接请求:使用Listen方法开始监听客户端连接请求。 ``` listener.Listen(100); ``` 这里设置最大连接数为100,即同时最多允许100个客户端连接。 5. 接受连接请求:使用Accept方法接受客户端连接请求,并返回一个新的Socket对象,用于与客户端进行通讯。 ``` Socket handler = listener.Accept(); ``` 这里使用了一个while循环,可以接受多个客户端连接请求。 ``` while (true) { Socket handler = listener.Accept(); // 处理客户端请求 } ``` 注意:在处理完客户端请求后,需要关闭Socket对象。 可以根据业务需求,对接收到的客户端请求进行解析和处理。例如,可以使用StreamReader和StreamWriter类来读取和写入数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值