Bootstrap

C#中异步SOCKET发送数据时内存问题

做CS的开发一直都是这样的方式:

server端用 C++编写,采用IOCP机制处理大量客户端连接、数据接收发送的问题

client端用 C++ 或C# 写,没什么特殊要求。


最近工作时间上比较宽裕,决定采用新的方式来处理服务端的工作: C# + SOCKET异步机制(.net里没有IOCP的直接支持)

目前正可行性分析阶段,第一步的工作:接收3W个SOCKET连接, 结果还是不错的,很快就建立起来了,速度也可以。

但是第二步测试,接收、发送数据时,就发生了点问题:

   运行的SERVER程序在较短的时间内就占用了大量的内存!


我的测试环境:i3 +2G内存 + Win732位

客户端创建5000个连接,每间隔1秒种对所有的连接发送、接收一次数据。每次发送20bytes到server。

服务端与客户端不在同一台机器上

一般情况下,程序的启动内存占用为4.5M ,运行5分钟后,SERVER程序内存占用超过 100M,并且还在不停的快速增长


在一台服务器上测试(2W个连接),4个小时内,把8G内存全部用光(从任务管理器上看,使用了7.9G内存)



先看SERVER端的完整代码:(大家可以COPY到自己的IDE里直接编译)

[csharp]  view plain copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Net.Sockets;  
  6.   
  7. namespace TestAsyncSendMem  
  8. {  
  9.     class Program  
  10.     {  
  11.         static TcpListener m_lisnter;  
  12.         static AsyncCallback m_acb = new AsyncCallback(DoAcceptSocketCallback);  
  13.         static void Main(string[] args)  
  14.         {  
  15.             m_lisnter = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 8001);  
  16.             m_lisnter.Start(5 * 1000);  
  17.   
  18.             try  
  19.             {  
  20.                 m_lisnter.BeginAcceptSocket(m_acb, null);  
  21.             }  
  22.             catch (Exception ex)  
  23.             {  
  24.                 m_lisnter.Stop();  
  25.                 m_lisnter = null;  
  26.   
  27.                 System.Diagnostics.Debug.WriteLine("BeginAcceptSocket err.Start fail!" + ex);  
  28.                 return;  
  29.             }  
  30.             Console.WriteLine("Begin receiving connection... Press any key to quit.");  
  31.   
  32.             Console.ReadKey();  
  33.   
  34.             m_lisnter.Stop();  
  35.         }  
  36.   
  37.         static void DoAcceptSocketCallback(IAsyncResult ar)  
  38.         {  
  39.             System.Net.Sockets.Socket s = null;  
  40.             try  
  41.             {  
  42.                 s = m_lisnter.EndAcceptSocket(ar);  
  43.             }  
  44.             catch (Exception ex)  
  45.             {  
  46.                 System.Diagnostics.Debug.WriteLine("End Accept socket err" + ex);  
  47.                 s = null;  
  48.             }  
  49.   
  50.             try  
  51.             {  
  52.                 m_lisnter.BeginAcceptSocket(m_acb, null);  
  53.             }  
  54.             catch (Exception ex)  
  55.             {  
  56.                 System.Diagnostics.Debug.WriteLine("after accept client socket,Re beginAcceptSocket fail." + ex);  
  57.             }  
  58.   
  59.             if (s != null)  
  60.             {  
  61.                 #region...  
  62.                 CTcpClientSync c = new CTcpClientSync(s);  
  63.                 Console.WriteLine(string.Format("accept client.{0}", c.Socket.RemoteEndPoint));  
  64.   
  65.                 if (c.BeginRcv() == true)  
  66.                 {  
  67.                     c.OnDisconnected += (CTcpClientSync client) =>  
  68.                     {  
  69.                         System.Diagnostics.Debug.WriteLine(string.Format("client {0} disconected", client.RemoteIP));  
  70.                     };  
  71.                 }  
  72.                 else  
  73.                 {  
  74.                     c.Stop();  
  75.                     System.Diagnostics.Debug.WriteLine(string.Format("accepted client {0} removed.cannot begin rcv", c.RemoteIP));  
  76.                 }  
  77.                 #endregion  
  78.             }  
  79.   
  80.         }  
  81.     }  
  82.   
  83.     public class CTcpClientSync  
  84.     {  
  85.         #region delegate  
;