详解通过.NET缓存提高TCP传输速度

在这里我们将介绍的是通过.NET缓存提高TCP传输速度,这也是提高网络性能的方法,希望对大家有所帮助。

成都创新互联公司坚持“要么做到,要么别承诺”的工作理念,服务领域包括:网站设计、成都网站制作、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的桥东网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!

.NET提供了一个NetworkStream 用于TCP 的读写,实际使用时发现直接操作效率很低,哪怕把TCP 的发送缓存和接受缓存设置很大也没有太大提高。后来在对 NetworkStream 读写前设置了缓存,性能一下子提高了很多。

从实际测试结果看设置自己的写缓存,对性能的提升最为显著。我分析了一下,其原因很可能是在向NetworkStream 序列化对象时,序列化程序调用了大量的Write 方法向NetworkStream写入数据,每次向NetworkStream写入数据,数据被首先写入TCP的发送缓存,并且由调用线程设置一个信号通知.Net framework 内部的TCP线程发送缓冲区中已经有数据,TCP线程被激活并读取发送缓冲区中的数据,组包并向网卡写入数据。频繁的调用 NetworkStream.Write 写入小块数据将导致调用线程和TCP线程反复切换,并大量触发网卡中断,导致发送效率低下。如果我们在发送前将数据缓存并按较大的数据块发送给TCP线程,则大大减少线程切换和网卡中断数量,从而大大提高传输效率。

问题到这里还没有结束,我们发送的对象往往较大,如果我们将发送对象全部序列化到buffer中再发送,那么势必占用大量内存,实际上我们无法忍受这种对内存无限制申请的行为,试想一个1G大小的对象,我们在发送前为它另外再开辟1个G的内存来缓存,对于系统来说简直是无法忍受。由于我们用.net 发送数据,我们在发送时需要将对象序列化到流中,而不能像 C/C++那样直接通过指针来读取数据(当然你也可以用unsafe代码,但这种方式会带来其他问题,而且并不为大家所推荐),所以我们需要开发一个专门用 TCP 发送缓存的流来处理读写前的缓存。为此我开发了一个 TcpCacheStream 类,这个类被用在读写 NetworkStream 前先进行缓存。

调用方法很简单

发送过程  

 
 
 
  1. object msg;  
  2. //初始化 msg 过程省略  
  3. System.Net.Sockets.NetworkStream _ClientStream;  
  4. //初始化 _ClientStream 过程省略  
  5.    
  6. //创建TcpCacheStream   
  7. TcpCacheStream tcpStream = new TcpCacheStream(_ClientStream);  
  8.    
  9. //二进制序列化 msg 对象到 TcpCacheStream   
  10. IFormatter formatter = new BinaryFormatter();  
  11. formatter.Serialize(tcpStream, msg);  
  12.    
  13. //将缓存中最后一包的数据发送出去  
  14. tcpStream.Flush(); 

接收过程

 
 
 
  1. System.Net.Sockets.NetworkStream _ClientStream;  
  2. //初始化 _ClientStream 过程省略  
  3.    
  4. //创建TcpCacheStream   
  5. TcpCacheStream tcpStream = new TcpCacheStream(_ClientStream);  
  6.    
  7. //从 TcpCacheStream 二进制反序列化  
  8. IFormatter formatter = new BinaryFormatter();  
  9. objcet result = formatter.Deserialize(tcpStream); 

TcpCacheStream 类为调用者封装了缓存的过程,这个缓存过程实际并不复杂,发送时数据先写入TcpCacheStream的buf中,当buf满后才向NetworkStream 写入数据,否则只缓存。由于最后一包不能保证正好填满buf,我们在写入数据后一定要调用 Flush 方法,将所有数据都发送出去。接收的过程反过来,如果buf中没有数据,就先将数据读入到buf中,然后再COPY给调用者,如果已经有数据则直接COPY给调用者。

TcpCacheStream 的代码如下:

 
 
 
  1. [Serializable]  
  2.     public class TcpCacheStream : Stream  
  3.     {  
  4.         #region Private fields  
  5.         const int BUF_SIZE = 4096;  
  6.         private byte[] _Buf = new byte[BUF_SIZE];  
  7.          private MemoryStream _CacheStream = new MemoryStream(BUF_SIZE);  
  8.         private NetworkStream _NetworkStream;  
  9.          private int _BufLen = 0;  
  10.         #endregion  
  11.         #region Private properties  
  12.         private MemoryStream CacheStream  
  13.         {  
  14.             get 
  15.             {  
  16.                 return _CacheStream;  
  17.             }  
  18.         }  
  19.    
  20.         #endregion  
  21.        #region Public properties  
  22.         ///   
  23.         /// get or set the Network Stream  
  24.         ///   
  25.         public NetworkStream NetworkStream  
  26.         {  
  27.             get 
  28.             {  
  29.                 return _NetworkStream;  
  30.             }  
  31.         }  
  32.         #endregion  
  33.         public TcpCacheStream(NetworkStream networkStream)  
  34.         {  
  35.             _NetworkStream = networkStream;  
  36.         }  
  37.         #region Implement stream class  
  38.         public override bool CanRead  
  39.         {  
  40.             get 
  41.             {  
  42.                 return true;  
  43.             }  
  44.         }  
  45.         public override bool CanSeek  
  46.         {  
  47.             get 
  48.             {  
  49.                 return false;  
  50.             }  
  51.         }  
  52.    
  53.         public override bool CanWrite  
  54.         {  
  55.             get 
  56.             {  
  57.                 return true;  
  58.             }  
  59.         }  
  60.          public override void Flush()  
  61.         {  
  62.             NetworkStream.Write(_Buf, 0, _BufLen);  
  63.             NetworkStream.Flush();  
  64.         }  
  65.          public override long Length  
  66.         {  
  67.             get 
  68.             {  
  69.                 throw new Exception("This stream can not seek!");  
  70.             }  
  71.         }  
  72.    
  73.         public override long Position  
  74.         {  
  75.             get 
  76.             {  
  77.                 throw new Exception("This stream can not seek!");  
  78.             }  
  79.    
  80.             set 
  81.             {  
  82.                 throw new Exception("This stream can not seek!");  
  83.             }  
  84.         }  
  85.    
  86.         public override int Read(byte[] buffer, int offset, int count)  
  87.         {  
  88.             int len = 0;  
  89.    
  90.             //If cache is not empty, read from cache  
  91.             if (CacheStream.Length > CacheStream.Position)  
  92.             {  
  93.                 len = CacheStream.Read(buffer, offset, count);  
  94.                 return len;  
  95.             }  
  96.    
  97.             //Fill cache  
  98.             len = NetworkStream.Read(_Buf, 0, BUF_SIZE);  
  99.    
  100.             if (len == 0)  
  101.             {  
  102.                 return 0;  
  103.             }  
  104.    
  105.             CacheStream.Position = 0;  
  106.             CacheStream.Write(_Buf, 0, len);  
  107.             CacheStream.SetLength(len);  
  108.             CacheStream.Position = 0;  
  109.    
  110.             len = CacheStream.Read(buffer, offset, count);  
  111.    
  112.             return len;  
  113.         }  
  114.    
  115.         public override long Seek(long offset, SeekOrigin origin)  
  116.         {  
  117.             throw new Exception("This stream can not seek!");  
  118.         }  
  119.    
  120.         public override void SetLength(long value)  
  121.         {  
  122.             throw new Exception("This stream can not seek!");  
  123.         }  
  124.    
  125.         public override void Write(byte[] buffer, int offset, int count)  
  126.         {  
  127.             if (offset + count > buffer.Length)  
  128.             {  
  129.                 throw new ArgumentException("Count + offset large then buffer.Length");  
  130.             }  
  131.    
  132.             int remain = count - (BUF_SIZE - _BufLen);  
  133.    
  134.             if (remain < 0)  
  135.             {  
  136.                 Array.Copy(buffer, offset, _Buf, _BufLen, count);  
  137.                 _BufLen = BUF_SIZE + remain;  
  138.             }  
  139.             else 
  140.             {  
  141.                 Array.Copy(buffer, offset, _Buf, _BufLen, BUF_SIZE - _BufLen);  
  142.                 NetworkStream.Write(_Buf, 0, _Buf.Length);  
  143.    
  144.                 Array.Copy(buffer, offset + BUF_SIZE - _BufLen, _Buf, 0, remain);  
  145.    
  146.                 _BufLen = remain;  
  147.             }  
  148.         }  
  149.          #endregion  
  150.     } 
            

标题名称:详解通过.NET缓存提高TCP传输速度
标题来源:http://www.csdahua.cn/qtweb/news19/258319.html

网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网